En el año 2008 Apple anunció y lanzo el iPhone SDK 2.0. Este evento inició otra revolución dentro del desarrollo de software y así nació una nueva generación de desarrolladores, quienes ahora son reconocidos como desarrolladores iOS.
Muchos desarrolladores nunca antes habían utilizado Objective-C y ese fue el primer reto que Apple tenía para ellos. A pesar de una sintaxis desconocida y un manejo de memoria manual, éste fue inmensamente exitoso, ayudando a poblar la App Store con decenas de miles de aplicaciones. Apple continuamente mejoraba Objective-C con cada nueva versión, añadiendo bloques y literales (literals), agregando manejo de memoria simplificado con recuento de referencias automático y muchas otras características que indican un lenguaje de programación moderno.
Luego de seis años trabajando y mejorando Objective-C, Apple decidió retar nuevamente a los desarrolladores. Una vez más, los desarrolladores iOS tendrán que aprender un nuevo lenguaje de programación: Swift. Swift elimina la gestión insegura de punter e introduce nuevas e importantes características, mientras mantiene la interacción con ambos Objective-C y C.
Swift 1.0 es una plataforma de desarrollo estable y fuerte, la cual es seguro que evolucionará de manera interesante en los próximos años. Es el momento perfecto para comenzar a explorar este nuevo lenguaje ya que es, obviamente, el futuro del desarrollo iOS.
Para comenzar a explorar Swift lo que necesitas es descargar XCode 6 de la App Store y crear una zona de juegos para experimentar. Todos los ejemplos que se mencionan a continuacion fueron realizados de ésta manera.
El sitio web de Apple Swift es la mejor referencia para aprender sobre programación Swift. Verás que es muy valiosa, y hasta que estés completamente al día con el desarrollo Swift Creo que visitaras el sitio con frecuencia.
Para declarar una variable en Swift se usa la palabra clave var
.
var x = 1var s = "Hello"
Notarás que las dos variables s
y x
son de diferentes tipos. x
es un Número Entero, mientras que “s” es una Cadena de Caracteres. Swift es un tipo de lenguaje seguro y deducirá los tipos de variables del valor asignado. Si deseas que tu código sea más legible, puedes anotar opcionalmente el tipo de variable:
var y: Inty = 2
Las constantes son similares pero se declaran usando let
en lugar de var
. No es necesario saber el valor de una constante al momento de la compilación pero debes asignarle un valor exactamente una vez.
let c1 = 1 // Constante conocida al momento de la compilación var v = arc4random()let c2 = v // Constante conocida solo en momento de ejecución
Como su nombre lo indica, son inmutables, por esto el siguiente código causará un error al momento de compilación.
let c = 1c = 3 // error
Otros tipos también pueden ser declarados como constantes. Por ejemplo, el siguiente código declara una matriz como una constante y, si intentas modificar cualquiera de los elementos, el compilador Swift reportará un error:
var arr2 = [4, 5, 6]arr2[0] = 8print (arr2) // [8, 5, 6] let arr = [1, 2, 3]a[0] = 5 // error
Es necesario inicializar las constantes cuando se están declarando, al igual que es necesario inicializar las variables antes de usarlas. Así que, ¿dónde está el equivalente nil
de Objective-C? Swift introduce valores opcionales. Los valores opcionales pueden tener un valor o ser nil
. Si observas el siguiente código, vas a notar que x
fue asignada como valor Opcional
de 2014
. Esto significa que el compilador Swift sabía que x
podría ser nil
.
var s = "2014"var x = s.toInt()print(x) // Optional(2014)
Si haces un cambio en éste código y asignas el valor "abc"
a s
, el cual no se puede convertir a un número entero, vas a notar que x
es ahora un nil
.
var s = "abc"var x = s.toInt()print(x) // nil
¿El tipo de retorno de la función toInt()
es Int?
, el cual es un Int opcional. Vamos a tratar de llamar a una función estándar en x
:
var x = "2014".toInt()print(x.successor()) // error
El compilador señala un error, ya que x
es un opcional y podría ser potencialmente nil. Debemos probar x
primero, y asegurarnos de que la función sucessor
sea invocada en un número real, y no en un valor nil
:
var x = "2014".toInt()if x != nil{print(x!.successor()) // 2015}
Ten en cuenta que debemos desenvolver x
añadiendo un signo de exclamación (!). Cuando nos aseguramos que x
contiene un valor, podemos acceder a él. De lo contrario, obtendremos un error de ejecución. También podemos hacer lo que Swift llama optional binding, convirtiendo así lo opcional a una variable no-opcional
let x = "123".toInt()if let y = x{print(y)}
El código de la instrucción if
solo se ejecutará si x
tiene un valor, y es asignada a y
. Ten en cuenta que no necesitamos desenvolver y
, su tipo no opcional, ya que sabemos que x
no es nil
.
Revisa el tutorial Swift de Apple donde podrás leer en detalle sobre opcionales e interesantes características
En Objective-C, una cadena de formateo usualmente se hace con el método stringWithFormat::
NSString por user = @"Gabriel";
int days = 3;
NSString por s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];
Swift tiene una característica llamada interpolación de Cadenas que hace lo mismo, pero es más compacta y fácil de leer:
let user = "Gabriel"
let days = 3
let s = "posted by \(user) \(days) ago"
También puedes usar expresiones:
let width = 2
let height = 3
let s = "Area for square with sides \(width) and \(height) is \(width por height)"
La definición de Función en Swift es diferente a la de C. Una muestra de definición de función es la siguiente:
func someFunction(s:String, i: Int) -> Bool
{
... // code
}
Las funciones Swift son tipos de primera clase. Esto quiere decir que puedes asignar funciones a las variables, hacerlas pasar como parámetros para las funciones o hacerlas regresar tipos:
func stringLength(s:String) -> Int
{
return countElements(s)
}
func stringValue(s:String) -> Int
{
if let x = s.toInt()
{
return x
}
return 0
}
func doSomething(f:String -> Int, s:String) -> Int
{
return f(s).successor()
}
let f1 = stringLength
let f2 = stringValue
doSomething(f1, "123") // 4
doSomething(f2, "123") // 124
De nuevo, Swift infiere los tipos de f1 and f2 (String -> Int), Aunque los pudimos haber definido explícitamente:
let f1:String -> Int = stringLength
Las funciones también pueden regresar otras funciones:
func compareGreaterThan(a: Int, b: Int) -> Bool
{
return a > b
}
func compareLessThan(a: Int, b: Int) -> Bool
{
return a < b
}
func comparator(greaterThan:Bool) -> (Int, Int) -> Bool
{
if greaterThan
{
return compareGreaterThan
}
else
{
return compareLessThan
}
}
let f = comparator(true)
println(f(5, 9))
Las enumeraciones en Swift son mucho más ponderosas que en Objective-C. Como lo estructura Swift, pueden tener métodos y se pasan como valores:
enum MobileDevice : String{ case iPhone = "iPhone", Android = "Android", WP8 = "Windows Phone8", BB = "BlackBerry" func name() -> String { return self.toRaw() }}let m = MobileDevice.Androidprint(m.name()) // "Android"
A diferencia de Objective-C, las enumeraciones Swift pueden asignar cadenas, caracteres o flotantes como valores para cada miembro, aparte de números enteros. El método conveniente toRaw()
regresa el valor asignado a cada miembro.
Las enumeraciones también se pueden parametrizar:
enum Location{ case Address(street:String, city:String) case LatLon(lat:Float, lon:Float) func description() -> String { switch self { case let .Address(street, city): return street + ", " + city case let .LatLon(lat, lon): return "(\(lat), \(lon))" } }}let loc1 = Location.Address(street: "2070 Fell St", city: "San Francisco")let loc2 = Location.LatLon(lat: 23.117, lon: 45.899)print(loc1.description()) // "2070 Fell St, San Francisco"print(loc2.description()) // "(23.117, 45.988)"
Las tuplas agrupan valores múltiples en un único valor compuesto. Los valores dentro de una tupla pueden ser de cualquier tipo y no tiene que ser del mismo tipo entre ellos.
let person = ("Gabriel", "Kirkpatrick")print(person.0) // Gabriel
También puedes darle nombre a los elementos de tuplas individuales:
let person = (first: "Gabriel", last: "Kirkpatrick")print(person.first)
Las tuplas son extremadamente convenientes como tipos de regreso para funciones que necesitan regresar más de un valor:
func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int){ return (a/b, a%b)}print(intDivision(11, 3)) // (3, 2)let result = intDivision(15, 4)print(result.remainder) // 3
A diferencia de Objective-C, Swift no requiere que crees documentos de interfaz e implementación por separado para clases y estructuras personalizadas. Mientras aprendes sobre Swift, aprenderás a definir una clase o estructura en un solo documento y la interfaz externa para esa clase o estructura se hace disponible automáticamente para el uso de otro código.
Definir Clases
Las definiciones de clase son my sencillas:
class Bottle
{
var volume: Int = 1000
func description() -> String
{
return "This bottle has \(volume) ml"
}
}
let b = Bottle()
print(b.description())
Como puedes ver, declaración e implementación están en el mismo documento. Swift ya no utiliza un encabezado ni documentos de implementación. Agreguemos una etiqueta a nuestro ejemplo:
class Bottle
{
var volume: Int = 1000
var label:String
func description() -> String
{
return "This bottle of \(label) has \(volume) ml"
}
}
El compilador se quejará, ya que la etiqueta es una variable no-opcional, y ésta no mantendrá un valor cuando se ejemplifica una Bottle (Botella). Necesitamos agregar un inicializador:
class Bottle
{
var volume: Int = 1000
var label:String
init(label:String)
{
self.label = label
}
func description() -> String
{
return "This bottle of \(label) has \(volume) ml"
}
}
O podríamos usar tipo Opcional para una propiedad, el cual no necesita ser inicializado. En el siguiente ejemplo convertimos en volumen un Número entero Opcional:
class Bottle
{
var volume: Int?
var label:String
init(label:String)
{
self.label = label
}
func description() -> String
{
if self.volume != nil
{
return "This bottle of \(label) has \(volume!) ml"
}
else
{
return "A bootle of \(label)"
}
}
}
Estructuras
El lenguaje Swift también tiene structs, pero son mucho más flexibles que en Objective-C. El siguiente tutorial de código define un struct:
struct Seat
{
var row: Int
var letter:String
init (row: Int, letter:String)
{
self.row = row
self.letter = letter
}
func description() -> String
{
return "\(row)-\(letter)"
}
}
Como las clases en Swift, las estructuras pueden tener métodos, propiedades, inicializadores y se ajustan a los protocolos. La diferencia principal entre clases y estructuras es que las clases se pasan por referencia, mientras que las estructuras lo hacen por valor.
Este ejemplo demuestra el pasar las clases por referencia:
let b = Bottle()
print(b.description()) // "b" bottle has 1000 ml
var b2 = b
b.volume = 750
print(b2.description()) // "b" and "b2" bottles have 750 ml
Si intentamos hacer algo similar con struct, notarás que las variables se pasan con valores:
var s1 = Seat(row: 14, letter:"A")
var s2 = s1
s1.letter = "B"
print(s1.description()) // 14-B
print(s2.description()) // 14-A
¿Cuándo debemos usar struct y cuándo usamos class? Al igual que en Objective-C y C, usa structs cuando necesites agrupar algunos valores y espera que sean copiados en vez de referenciados o colores RGB.
La instancia de una clase es conocida tradicionalmente como un objeto. Sin embargo, las clases y estructuras Swift son mucho más cercanas en funcionalidad que en otros lenguajes y se puede aplicar mucha funcionalidad a instancias de tipo estructura o clase. Por esto, el término más general utilizado en referencia Swift es instancia, el cual se aplica a cualquiera de estos dos.
Hay muchas cosas más importantes y nuevas que aprender en Swift como programación genérica, interacción con las bibliotecas Objective-C, cierres, optional chaining y sobrecarga de operadores. Un solo tutorial no puede describir completamente un nuevo lenguaje, pero añadiremos mucho más sobre programación Swift. Sin embargo, creo que esta lectura rápida ayudará a muchos desarrolladores Objective-C, quienes no han encontrado el tiempo, ni detalles de aprendizaje sobre el lenguaje Swift, ponte en marcha y deja que Swift te lleve a nuevas alturas.