SlideShare una empresa de Scribd logo
1 de 7
Descargar para leer sin conexión
WORKSHOP IOS:
Closures, generics & operators
Organizadores
 Alberto Irurueta Carro
Objetivos
 Entender el funcionamiento de generics
 Revisar el uso de Protocols y operadores con generics
REPOSITORIO
El repositorio del workshop lo podéis encontrar en:
https://github.com/albertoirurueta/swift-protocols-and-generics-workshop
Generics
Generics permite implementar código en Swift que puede ser reutilizado con distintos tipos de datos (e
incluso para tipos de datos que no estén definidos pero sigan algún tipo de protocolo).
Por ejemplo, los arrays y diccionarios en Swift son structs que usan generics, de modo que podemos hacer
instancias para contener cualquier tipo de datos.
Para crear una clase que utilice generics, debe usarse la sintaxis <Tipo1, Tipo2, ...> donde Tipo1, Tipo2
son los tipos a los que nos referiremos dentro de una clase o función.
Si queremos restringir que que los tipos genéricos sean una subclase de un tipo determinado, o
implementen cierto protocolo puede usarse la sintaxis <Tipo : Protocolo>, <Tipo : Clase>
Ejemplo:
Container.swift
import Foundation
/**
Contenedor de un objeto cualquiera de tipo T.
*/
public class Container<T> {
/**
Valor interno almacenado por esta clase.
*/
private var _value: T
/**
Constructor.
- parameter value: valor inicial proporcionado.
*/
public init(value: T) {
_value = value
}
/**
Obtiene o establece el valor interno de esta clase.
*/
public var value: T {
get{
return _value
}
set {
_value = newValue
}
}
}
En el código de este ejemplo, podemos crear instancias de Container para contener cualquier tipo de objeto.
Swift infiere el tipo T a partir del objeto proporcionado en el constructor, tal y como se ve en el siguiente
test:
ContainerTests.swift
...
func testConstructorAndValue() {
let value1 = "hello"
let container1 = Container<String>(value: value1)
//comprobamos valor inicial
XCTAssertEqual(value1, container1.value)
//establecemos nuevo valor
container1.value = "bye"
//comprobamos
XCTAssertEqual(container1.value, "bye")
let container2 = Container<Int>(value: 1)
//valor inicial
XCTAssertEqual(container2.value, 1)
//nuevo valor
container2.value = 10
//comprobamos
XCTAssertEqual(container2.value, 10)
}
Operadores
public protocol Equatable {
public static func ==(lhs: Self, rhs: Self) -> Bool
}
public protocol Comparable : Equatable {
public static func <(lhs: Self, rhs: Self) -> Bool
public static func <=(lhs: Self, rhs: Self) -> Bool
public static func >=(lhs: Self, rhs: Self) -> Bool
public static func >(lhs: Self, rhs: Self) -> Bool
}
public func ><T : Comparable>(lhs: T, rhs: T) -> Bool
public func <=<T : Comparable>(lhs: T, rhs: T) -> Bool
public func >=<T : Comparable>(lhs: T, rhs: T) -> Bool
Sorter
En el repositorio hemos creado una serie de clases que utilizan generics, closures y protocols para ordenar
cualquier tipo de datos.
Se ha creado una clase base Sorter, y subclases con distintos algoritmos de ordenación implementados
(StraightInsertationSorter, ShellSorter, QuicksortSorter, HeapsortSorter, FoundationSorter)
En el repositorio está el código completo de estas clases, pero aquí os pongo algunos aspectos interesantes
a considerar:
 En Swift no existen las clases abstractas. O bien se utiliza un protocol, o bien usamos un constructor
privado o internal para impedir la instanciación directa, como se ha hecho en el caso de Sorter.
Sorter.swift
/**
Constructor.
Es privado para impedir la instanciación directa de esta clase.
*/
internal init() { }
 Por comodidad en Sorter se han añadido métodos estáticos de factoría para crear instancias de
subclases según el algoritmo de ordenación deseado.
/**
Método de factoría para crear instancias de Sorter que utilicen el método
de ordenación indicado.
- param method: método de ordenación.
*/
public static func create(method: SortingMethod) -> Sorter {
switch method {
case .foundation:
return FoundationSorter()
case .heapsort:
return HeapsortSorter()
case .quicksort:
return QuicksortSorter()
case .shell:
return ShellSorter()
case .straightInsertion:
return StraightInsertionSorter()
}
}
/**
Método de factoría para crear instancias de Sorter con el método de
ordenación por defecto.
*/
public static func create() -> Sorter {
return create(method: DefaultSortingMethod)
}
 Errores: Hemos definido un enumerador que implementa Error para gestionar los errores que
algunos métodos pueden lanzar en algunas situaciones
/**
Tipos de error que pueden obtenerse al ordenar arrays.
*/
public enum SorterError : Error {
/**
Si la posición fromIndex es mayor que la posición toIndex
*/
case illegalIndices
/**
Si se proporcionan valores de índices fuera del rango de índices
accesibles por el array proporcionado (entre 0 y su count - 1).
*/
case indexOutOfBounds
/**
Si la ordenación falla por cualquier otro motivo.
*/
case sortingError
}
 Algunos métodos modifican los parámetros de entrada. Por defecto en Swift los parámetros de
entrada se pasan por copia, lo cual, en el caso de los structs implica que si se modificasen, el
resultado no quedaría reflejado tras la ejecución de un método. Para ello puede indicarse que un
parámetro es inout para pasar tanto clases como structs por referencia.
public func sort<T>(_ array: inout [T], fromIndex from: Int,
toIndex to: Int, comparator: Comparator) throws {
try sort(&array, fromIndex: from, toIndex: to,
comparator: { (o1, o2) -> Int in
return comparator.compare(o1, o2)
})
}
 Para pasar un parámetro inout por referencia, dbee usarse &, como se ve en el ejemplo anterior
 Si un método lanza algún tipo de excepción o ejecuta un método con try sin recoger su excepción,
debe indicarse mediante throws en su declaración
public override func sort<T>(_ array: inout [T], fromIndex: Int,
toIndex: Int,
comparator: (_ o1: T, _ o2: T) -> Int) throws {
guard fromIndex <= toIndex else {
throw SorterError.illegalIndices
}
guard fromIndex >= 0 && toIndex <= array.count else {
throw SorterError.indexOutOfBounds
}
...
 Para llamar a un método que lanza excepciones, debe usarse try, try? o try!. Try nos permite
relanzar una excepción o bien llamar al método dentro de un bloque do... catch para capturarla.
try? nos permite obtener el resultado de un método que puede lanzar una excepción como un
optional, u obtener nil si se produce la excepción, try! permite obtener el resultado de la ejecución
del método asumiendo que éste nunca va a fallar (si se produjese una excepción se detendría la
ejecución).
public func sort<T : Comparable>(_ array: inout [T], fromIndex from: Int,
toIndex to: Int) throws {
try sort(&array, fromIndex: from, toIndex: to,
comparator: { (o1, o2) -> Int in
return Sorter.compare(o1, o2)
})
}
...
try! sorter.sort(&array, fromIndex: fromIndex, toIndex: toIndex)
 Si el método devuelve void, también puede usarse do... catch{} pero se considera mala práctica
no hacer nada en un bloque catch y además empeora la cobertura
public func sort<T>(_ array: inout [T],
comparator c: (_ o1: T, _ o2: T) -> Int) {
do {
try sort(&array, fromIndex: 0, toIndex: array.count, comparator: c)
} catch { }
}
 En el sorter hay métodos sort que usan closures, que usan Protocols, que usan generics de tipos
Comparables. En el caso de las closures y los protocols, nos permiten definir cómo se realiza la
comparación entre CUALQUIER tipo de datos, y permiten incluso realizar cosas como invertir el
orden de ordenado. En el caso de generics con comparables, se nos simplifica el uso de la clase,
ya que no es necesario proporcionar un comparador.
 En un for puede indicarse un range para indicar los valores sobre los que se iteran
Sin embargo, si el valor inicial es mayor que el final, el range no puede crearse y la ejecución falla.
Si se necesitase crear un range en sentido decreciente, puede hacerse con la función stride (from:
to: by:) o stride(from: through: by:). En el primer caso el valor final es exclusivo y en el segundo
es inclusivo. En cualquier caso, recordad que un for siempre puede expresarse como un while junto
con variables sobre las que se iteran.
 En el caso de FoundationSorter se nos proporcionan parámetros o1 y o2 de tipo T, que no tienen
por qué ser Comparables. Podemos forzar que T sea Comparable con una función auxiliar que
defina un generic como T como Comparable y haciendo el cast dentro de un if para así poder usar
los operadores < y > con un tipo T.
public override func sort<T>(_ array: inout [T], fromIndex: Int,
toIndex: Int,
comparator: (_ o1: T, _ o2: T) -> Int) {
array.sort { (o1, o2) -> Bool in
FoundationSorter.compare(o1, o2, Int.self)
}
}
private static func compare<T: Comparable>(_ o1: Any, _ o2: Any,
_ type: T.Type) -> Bool{
if let c1 = o1 as? T, let c2 = o2 as? T {
return c1 < c2
} else {
return false
}
}
 Para poder implementar Comparators que puedan usar los operadores < y > en SwiftSorter hemos
definido las siguientes clases auxiliares donde se hace un cast de un tipo T cualquiera a un tipo U
comparable
class ComparatorAscendant<U : Comparable> :
swiftProtocolsAndGenerics.Comparator {
public func compare<T>(_ o1: T, _ o2: T) -> Int {
if let c1 = o1 as? U, let c2 = o2 as? U {
if c1 < c2 {
return -1
} else if c1 == c2 {
return 0
} else {
return 1
}
} else {
return -1
}
}
}
class ComparatorDescendant<U : Comparable> :
swiftProtocolsAndGenerics.Comparator {
public func compare<T>(_ o1: T, _ o2: T) -> Int {
if let c1 = o1 as? U, let c2 = o2 as? U {
if c1 < c2 {
return 1
} else if c1 == c2 {
return 0
} else {
return -1
}
} else {
return -1
}
}
}
class ComparatorAndAveragerAscendant<U : Comparable> :
swiftProtocolsAndGenerics.ComparatorAndAverager {
public func compare<T>(_ o1: T, _ o2: T) -> Int {
if let c1 = o1 as? U, let c2 = o2 as? U {
if c1 < c2 {
return -1
} else if c1 == c2 {
return 0
} else {
return 1
}
} else {
return -1
}
}
public func average<T>(_ o1: T, _ o2: T) -> T {
if let i1 = o1 as? Int, let i2 = o2 as? Int {
return ((i1 + i2) / 2) as! T
} else {
return 0 as! T
}
}
}
 También se han creado las clases auxiliares para el caso de Ints
class IntComparatorAscendant : ComparatorAscendant<Int> { }
class IntCompaaratorDescendant : ComparatorDescendant<Int> { }
class IntComparatorAndAveragerAscendant :
ComparatorAndAveragerAscendant<Int> { }

Más contenido relacionado

La actualidad más candente

La actualidad más candente (19)

Clase 4 JAVA 2012
Clase 4 JAVA 2012Clase 4 JAVA 2012
Clase 4 JAVA 2012
 
Statement
StatementStatement
Statement
 
Ajax
AjaxAjax
Ajax
 
Comandos de java
Comandos de javaComandos de java
Comandos de java
 
Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
 
Introduccion java
Introduccion javaIntroduccion java
Introduccion java
 
Funciones en C++
Funciones en C++Funciones en C++
Funciones en C++
 
P1C5 Lenguaje de Expresiones
P1C5 Lenguaje de ExpresionesP1C5 Lenguaje de Expresiones
P1C5 Lenguaje de Expresiones
 
Persistencia De Objetos(Hibernate)
Persistencia De Objetos(Hibernate)Persistencia De Objetos(Hibernate)
Persistencia De Objetos(Hibernate)
 
Semana 5 Java Swing
Semana 5   Java SwingSemana 5   Java Swing
Semana 5 Java Swing
 
Constructores en java(grupo 8)
Constructores en java(grupo 8)Constructores en java(grupo 8)
Constructores en java(grupo 8)
 
Introducción a Java Persistence API
Introducción a Java Persistence APIIntroducción a Java Persistence API
Introducción a Java Persistence API
 
comandos
comandoscomandos
comandos
 
J Flex Cup
J Flex CupJ Flex Cup
J Flex Cup
 
Funciones
FuncionesFunciones
Funciones
 
Unidad6 funciones
Unidad6 funcionesUnidad6 funciones
Unidad6 funciones
 
Multitarea e hilos en java con ejemplos
Multitarea e hilos en java con ejemplosMultitarea e hilos en java con ejemplos
Multitarea e hilos en java con ejemplos
 
Programa Java que gestiona los productos que comercializan varios viveros
Programa Java que gestiona los productos que comercializan varios viverosPrograma Java que gestiona los productos que comercializan varios viveros
Programa Java que gestiona los productos que comercializan varios viveros
 
8448148681
84481486818448148681
8448148681
 

Destacado

Workshop 11: Trendy web designs & prototyping
Workshop 11: Trendy web designs & prototypingWorkshop 11: Trendy web designs & prototyping
Workshop 11: Trendy web designs & prototypingVisual Engineering
 
Workshop 2: JavaScript Design Patterns
Workshop 2: JavaScript Design PatternsWorkshop 2: JavaScript Design Patterns
Workshop 2: JavaScript Design PatternsVisual Engineering
 
Workshop 18: CSS Animations & cool effects
Workshop 18: CSS Animations & cool effectsWorkshop 18: CSS Animations & cool effects
Workshop 18: CSS Animations & cool effectsVisual Engineering
 
Unlock The Value Of Your Microsoft and SAP Investments
Unlock The Value Of Your Microsoft and SAP InvestmentsUnlock The Value Of Your Microsoft and SAP Investments
Unlock The Value Of Your Microsoft and SAP InvestmentsSAP Technology
 
Change document display
Change document displayChange document display
Change document displayRadosław Gref
 
Multithreading 101
Multithreading 101Multithreading 101
Multithreading 101Tim Penhey
 
JavaScript for ABAP Programmers - 7/7 Functional Programming
JavaScript for ABAP Programmers - 7/7 Functional ProgrammingJavaScript for ABAP Programmers - 7/7 Functional Programming
JavaScript for ABAP Programmers - 7/7 Functional ProgrammingChris Whealy
 
Workshop 24: React Native Introduction
Workshop 24: React Native IntroductionWorkshop 24: React Native Introduction
Workshop 24: React Native IntroductionVisual Engineering
 
Automated Testing Of Web Applications Using XML
Automated  Testing Of  Web  Applications Using  XMLAutomated  Testing Of  Web  Applications Using  XML
Automated Testing Of Web Applications Using XMLdiongillard
 
Getting Started with OpenUI5 (San Francisco State University)
Getting Started with OpenUI5 (San Francisco State University)Getting Started with OpenUI5 (San Francisco State University)
Getting Started with OpenUI5 (San Francisco State University)Alexander Graebe
 
Introduction to Design Thinking
Introduction to Design ThinkingIntroduction to Design Thinking
Introduction to Design ThinkingBlackvard
 
Workhop iOS 1: Fundamentos de Swift
Workhop iOS 1: Fundamentos de SwiftWorkhop iOS 1: Fundamentos de Swift
Workhop iOS 1: Fundamentos de SwiftVisual Engineering
 
SAP for Utilities 2015 FINAL HOTLIST
SAP for Utilities 2015 FINAL HOTLISTSAP for Utilities 2015 FINAL HOTLIST
SAP for Utilities 2015 FINAL HOTLISTJonathan Toomey
 
Workshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IWorkshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IVisual Engineering
 
Consuming Data With HANA XS
Consuming Data With HANA XSConsuming Data With HANA XS
Consuming Data With HANA XSBlackvard
 

Destacado (20)

Workshop 11: Trendy web designs & prototyping
Workshop 11: Trendy web designs & prototypingWorkshop 11: Trendy web designs & prototyping
Workshop 11: Trendy web designs & prototyping
 
Workshop 6: Designer tools
Workshop 6: Designer toolsWorkshop 6: Designer tools
Workshop 6: Designer tools
 
Workshop 2: JavaScript Design Patterns
Workshop 2: JavaScript Design PatternsWorkshop 2: JavaScript Design Patterns
Workshop 2: JavaScript Design Patterns
 
Workshop 18: CSS Animations & cool effects
Workshop 18: CSS Animations & cool effectsWorkshop 18: CSS Animations & cool effects
Workshop 18: CSS Animations & cool effects
 
Unlock The Value Of Your Microsoft and SAP Investments
Unlock The Value Of Your Microsoft and SAP InvestmentsUnlock The Value Of Your Microsoft and SAP Investments
Unlock The Value Of Your Microsoft and SAP Investments
 
Change document display
Change document displayChange document display
Change document display
 
Workshop 16: EmberJS Parte I
Workshop 16: EmberJS Parte IWorkshop 16: EmberJS Parte I
Workshop 16: EmberJS Parte I
 
CDS Unit Testing
CDS Unit TestingCDS Unit Testing
CDS Unit Testing
 
Hana sql
Hana sql Hana sql
Hana sql
 
Multithreading 101
Multithreading 101Multithreading 101
Multithreading 101
 
JavaScript for ABAP Programmers - 7/7 Functional Programming
JavaScript for ABAP Programmers - 7/7 Functional ProgrammingJavaScript for ABAP Programmers - 7/7 Functional Programming
JavaScript for ABAP Programmers - 7/7 Functional Programming
 
Workshop 24: React Native Introduction
Workshop 24: React Native IntroductionWorkshop 24: React Native Introduction
Workshop 24: React Native Introduction
 
Automated Testing Of Web Applications Using XML
Automated  Testing Of  Web  Applications Using  XMLAutomated  Testing Of  Web  Applications Using  XML
Automated Testing Of Web Applications Using XML
 
Getting Started with OpenUI5 (San Francisco State University)
Getting Started with OpenUI5 (San Francisco State University)Getting Started with OpenUI5 (San Francisco State University)
Getting Started with OpenUI5 (San Francisco State University)
 
Python Intro
Python IntroPython Intro
Python Intro
 
Introduction to Design Thinking
Introduction to Design ThinkingIntroduction to Design Thinking
Introduction to Design Thinking
 
Workhop iOS 1: Fundamentos de Swift
Workhop iOS 1: Fundamentos de SwiftWorkhop iOS 1: Fundamentos de Swift
Workhop iOS 1: Fundamentos de Swift
 
SAP for Utilities 2015 FINAL HOTLIST
SAP for Utilities 2015 FINAL HOTLISTSAP for Utilities 2015 FINAL HOTLIST
SAP for Utilities 2015 FINAL HOTLIST
 
Workshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte IWorkshop 12: AngularJS Parte I
Workshop 12: AngularJS Parte I
 
Consuming Data With HANA XS
Consuming Data With HANA XSConsuming Data With HANA XS
Consuming Data With HANA XS
 

Similar a Workshop iOS 4: Closures, generics & operators

métodos procedimimientos estructuras de control java
métodos procedimimientos estructuras de control javamétodos procedimimientos estructuras de control java
métodos procedimimientos estructuras de control javaHenry Upla
 
TEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓN
TEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓNTEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓN
TEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓNAnyeni Garay
 
Scjp Jug Section 2 Flow Control
Scjp Jug Section 2 Flow ControlScjp Jug Section 2 Flow Control
Scjp Jug Section 2 Flow ControlJose Selman
 
Clase string y manejo de excepciones
Clase string y manejo de excepcionesClase string y manejo de excepciones
Clase string y manejo de excepcionesAliciaSandovalCamacho
 
Investigacion sobre carga de metodos
Investigacion sobre carga de metodosInvestigacion sobre carga de metodos
Investigacion sobre carga de metodosArisRojas4
 
Manuales ...
Manuales ...Manuales ...
Manuales ...elidetjc
 
Programación en c++
Programación en c++Programación en c++
Programación en c++andermijan
 
Sobrecarga de operadores
Sobrecarga de operadoresSobrecarga de operadores
Sobrecarga de operadoresr0na91
 
Introduccion a C++
Introduccion a C++Introduccion a C++
Introduccion a C++LenHugo
 
Comenzando a programar
Comenzando a programarComenzando a programar
Comenzando a programarRubén Loredo
 
Presentación introducción a Matlab y su estructura
Presentación introducción a Matlab y su estructuraPresentación introducción a Matlab y su estructura
Presentación introducción a Matlab y su estructuraJOSUEANIBALCOCHOJILH
 
Seccion Fundamentos SCJP
Seccion Fundamentos SCJPSeccion Fundamentos SCJP
Seccion Fundamentos SCJPjcherrera
 

Similar a Workshop iOS 4: Closures, generics & operators (20)

métodos procedimimientos estructuras de control java
métodos procedimimientos estructuras de control javamétodos procedimimientos estructuras de control java
métodos procedimimientos estructuras de control java
 
Programación básica
Programación básicaProgramación básica
Programación básica
 
TEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓN
TEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓNTEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓN
TEMA Nº 8: CONTROL DE EJECUCIÓN Y MANTENIMIENTO DE SESIÓN
 
Scjp Jug Section 2 Flow Control
Scjp Jug Section 2 Flow ControlScjp Jug Section 2 Flow Control
Scjp Jug Section 2 Flow Control
 
Clase string y manejo de excepciones
Clase string y manejo de excepcionesClase string y manejo de excepciones
Clase string y manejo de excepciones
 
C++
C++C++
C++
 
Investigacion sobre carga de metodos
Investigacion sobre carga de metodosInvestigacion sobre carga de metodos
Investigacion sobre carga de metodos
 
Manuales ...
Manuales ...Manuales ...
Manuales ...
 
Java 8
Java 8Java 8
Java 8
 
Programación en c++
Programación en c++Programación en c++
Programación en c++
 
Sobrecarga de operadores
Sobrecarga de operadoresSobrecarga de operadores
Sobrecarga de operadores
 
Introduccion a C++
Introduccion a C++Introduccion a C++
Introduccion a C++
 
Arreglos Expresiones y Control de Flujo
Arreglos Expresiones y Control de FlujoArreglos Expresiones y Control de Flujo
Arreglos Expresiones y Control de Flujo
 
Resulset
ResulsetResulset
Resulset
 
Comenzando a programar
Comenzando a programarComenzando a programar
Comenzando a programar
 
GRAFCET [Autoguardado].pptx
GRAFCET [Autoguardado].pptxGRAFCET [Autoguardado].pptx
GRAFCET [Autoguardado].pptx
 
Django y Python para todos
Django y Python para todosDjango y Python para todos
Django y Python para todos
 
Java básico
Java  básicoJava  básico
Java básico
 
Presentación introducción a Matlab y su estructura
Presentación introducción a Matlab y su estructuraPresentación introducción a Matlab y su estructura
Presentación introducción a Matlab y su estructura
 
Seccion Fundamentos SCJP
Seccion Fundamentos SCJPSeccion Fundamentos SCJP
Seccion Fundamentos SCJP
 

Más de Visual Engineering

Workshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSWorkshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSVisual Engineering
 
Workshop iOS 2: Swift - Structures
Workshop iOS 2: Swift - StructuresWorkshop iOS 2: Swift - Structures
Workshop iOS 2: Swift - StructuresVisual Engineering
 
Workshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideWorkshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideVisual Engineering
 
Workshop 25: React Native - Components
Workshop 25: React Native - ComponentsWorkshop 25: React Native - Components
Workshop 25: React Native - ComponentsVisual Engineering
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingVisual Engineering
 
Workshop 22: ReactJS Redux Advanced
Workshop 22: ReactJS Redux AdvancedWorkshop 22: ReactJS Redux Advanced
Workshop 22: ReactJS Redux AdvancedVisual Engineering
 
Workshop 22: React-Redux Middleware
Workshop 22: React-Redux MiddlewareWorkshop 22: React-Redux Middleware
Workshop 22: React-Redux MiddlewareVisual Engineering
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxVisual Engineering
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionVisual Engineering
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIVisual Engineering
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIVisual Engineering
 
Workshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJSWorkshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJSVisual Engineering
 
Workshop 9: BackboneJS y patrones MVC
Workshop 9: BackboneJS y patrones MVCWorkshop 9: BackboneJS y patrones MVC
Workshop 9: BackboneJS y patrones MVCVisual Engineering
 
Workshop 7: Single Page Applications
Workshop 7: Single Page ApplicationsWorkshop 7: Single Page Applications
Workshop 7: Single Page ApplicationsVisual Engineering
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testingVisual Engineering
 
Workshop 4: NodeJS. Express Framework & MongoDB.
Workshop 4: NodeJS. Express Framework & MongoDB.Workshop 4: NodeJS. Express Framework & MongoDB.
Workshop 4: NodeJS. Express Framework & MongoDB.Visual Engineering
 

Más de Visual Engineering (20)

Workshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJSWorkshop 27: Isomorphic web apps with ReactJS
Workshop 27: Isomorphic web apps with ReactJS
 
Workshop iOS 2: Swift - Structures
Workshop iOS 2: Swift - StructuresWorkshop iOS 2: Swift - Structures
Workshop iOS 2: Swift - Structures
 
Workshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideWorkshop 26: React Native - The Native Side
Workshop 26: React Native - The Native Side
 
Workshop 25: React Native - Components
Workshop 25: React Native - ComponentsWorkshop 25: React Native - Components
Workshop 25: React Native - Components
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Workshop 22: ReactJS Redux Advanced
Workshop 22: ReactJS Redux AdvancedWorkshop 22: ReactJS Redux Advanced
Workshop 22: ReactJS Redux Advanced
 
Workshop 22: React-Redux Middleware
Workshop 22: React-Redux MiddlewareWorkshop 22: React-Redux Middleware
Workshop 22: React-Redux Middleware
 
Workshop 21: React Router
Workshop 21: React RouterWorkshop 21: React Router
Workshop 21: React Router
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
Workshop 17: EmberJS parte II
Workshop 17: EmberJS parte IIWorkshop 17: EmberJS parte II
Workshop 17: EmberJS parte II
 
Workshop 15: Ionic framework
Workshop 15: Ionic frameworkWorkshop 15: Ionic framework
Workshop 15: Ionic framework
 
Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte III
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte II
 
Workshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJSWorkshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJS
 
Workshop 10: ECMAScript 6
Workshop 10: ECMAScript 6Workshop 10: ECMAScript 6
Workshop 10: ECMAScript 6
 
Workshop 9: BackboneJS y patrones MVC
Workshop 9: BackboneJS y patrones MVCWorkshop 9: BackboneJS y patrones MVC
Workshop 9: BackboneJS y patrones MVC
 
Workshop 7: Single Page Applications
Workshop 7: Single Page ApplicationsWorkshop 7: Single Page Applications
Workshop 7: Single Page Applications
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
 
Workshop 4: NodeJS. Express Framework & MongoDB.
Workshop 4: NodeJS. Express Framework & MongoDB.Workshop 4: NodeJS. Express Framework & MongoDB.
Workshop 4: NodeJS. Express Framework & MongoDB.
 

Workshop iOS 4: Closures, generics & operators

  • 1. WORKSHOP IOS: Closures, generics & operators Organizadores  Alberto Irurueta Carro Objetivos  Entender el funcionamiento de generics  Revisar el uso de Protocols y operadores con generics REPOSITORIO El repositorio del workshop lo podéis encontrar en: https://github.com/albertoirurueta/swift-protocols-and-generics-workshop Generics Generics permite implementar código en Swift que puede ser reutilizado con distintos tipos de datos (e incluso para tipos de datos que no estén definidos pero sigan algún tipo de protocolo). Por ejemplo, los arrays y diccionarios en Swift son structs que usan generics, de modo que podemos hacer instancias para contener cualquier tipo de datos. Para crear una clase que utilice generics, debe usarse la sintaxis <Tipo1, Tipo2, ...> donde Tipo1, Tipo2 son los tipos a los que nos referiremos dentro de una clase o función. Si queremos restringir que que los tipos genéricos sean una subclase de un tipo determinado, o implementen cierto protocolo puede usarse la sintaxis <Tipo : Protocolo>, <Tipo : Clase>
  • 2. Ejemplo: Container.swift import Foundation /** Contenedor de un objeto cualquiera de tipo T. */ public class Container<T> { /** Valor interno almacenado por esta clase. */ private var _value: T /** Constructor. - parameter value: valor inicial proporcionado. */ public init(value: T) { _value = value } /** Obtiene o establece el valor interno de esta clase. */ public var value: T { get{ return _value } set { _value = newValue } } } En el código de este ejemplo, podemos crear instancias de Container para contener cualquier tipo de objeto. Swift infiere el tipo T a partir del objeto proporcionado en el constructor, tal y como se ve en el siguiente test: ContainerTests.swift ... func testConstructorAndValue() { let value1 = "hello" let container1 = Container<String>(value: value1) //comprobamos valor inicial XCTAssertEqual(value1, container1.value) //establecemos nuevo valor container1.value = "bye" //comprobamos
  • 3. XCTAssertEqual(container1.value, "bye") let container2 = Container<Int>(value: 1) //valor inicial XCTAssertEqual(container2.value, 1) //nuevo valor container2.value = 10 //comprobamos XCTAssertEqual(container2.value, 10) } Operadores public protocol Equatable { public static func ==(lhs: Self, rhs: Self) -> Bool } public protocol Comparable : Equatable { public static func <(lhs: Self, rhs: Self) -> Bool public static func <=(lhs: Self, rhs: Self) -> Bool public static func >=(lhs: Self, rhs: Self) -> Bool public static func >(lhs: Self, rhs: Self) -> Bool } public func ><T : Comparable>(lhs: T, rhs: T) -> Bool public func <=<T : Comparable>(lhs: T, rhs: T) -> Bool public func >=<T : Comparable>(lhs: T, rhs: T) -> Bool Sorter En el repositorio hemos creado una serie de clases que utilizan generics, closures y protocols para ordenar cualquier tipo de datos. Se ha creado una clase base Sorter, y subclases con distintos algoritmos de ordenación implementados (StraightInsertationSorter, ShellSorter, QuicksortSorter, HeapsortSorter, FoundationSorter) En el repositorio está el código completo de estas clases, pero aquí os pongo algunos aspectos interesantes a considerar:  En Swift no existen las clases abstractas. O bien se utiliza un protocol, o bien usamos un constructor privado o internal para impedir la instanciación directa, como se ha hecho en el caso de Sorter. Sorter.swift /** Constructor. Es privado para impedir la instanciación directa de esta clase. */ internal init() { }
  • 4.  Por comodidad en Sorter se han añadido métodos estáticos de factoría para crear instancias de subclases según el algoritmo de ordenación deseado. /** Método de factoría para crear instancias de Sorter que utilicen el método de ordenación indicado. - param method: método de ordenación. */ public static func create(method: SortingMethod) -> Sorter { switch method { case .foundation: return FoundationSorter() case .heapsort: return HeapsortSorter() case .quicksort: return QuicksortSorter() case .shell: return ShellSorter() case .straightInsertion: return StraightInsertionSorter() } } /** Método de factoría para crear instancias de Sorter con el método de ordenación por defecto. */ public static func create() -> Sorter { return create(method: DefaultSortingMethod) }  Errores: Hemos definido un enumerador que implementa Error para gestionar los errores que algunos métodos pueden lanzar en algunas situaciones /** Tipos de error que pueden obtenerse al ordenar arrays. */ public enum SorterError : Error { /** Si la posición fromIndex es mayor que la posición toIndex */ case illegalIndices /** Si se proporcionan valores de índices fuera del rango de índices accesibles por el array proporcionado (entre 0 y su count - 1). */ case indexOutOfBounds /** Si la ordenación falla por cualquier otro motivo. */ case sortingError }  Algunos métodos modifican los parámetros de entrada. Por defecto en Swift los parámetros de entrada se pasan por copia, lo cual, en el caso de los structs implica que si se modificasen, el
  • 5. resultado no quedaría reflejado tras la ejecución de un método. Para ello puede indicarse que un parámetro es inout para pasar tanto clases como structs por referencia. public func sort<T>(_ array: inout [T], fromIndex from: Int, toIndex to: Int, comparator: Comparator) throws { try sort(&array, fromIndex: from, toIndex: to, comparator: { (o1, o2) -> Int in return comparator.compare(o1, o2) }) }  Para pasar un parámetro inout por referencia, dbee usarse &, como se ve en el ejemplo anterior  Si un método lanza algún tipo de excepción o ejecuta un método con try sin recoger su excepción, debe indicarse mediante throws en su declaración public override func sort<T>(_ array: inout [T], fromIndex: Int, toIndex: Int, comparator: (_ o1: T, _ o2: T) -> Int) throws { guard fromIndex <= toIndex else { throw SorterError.illegalIndices } guard fromIndex >= 0 && toIndex <= array.count else { throw SorterError.indexOutOfBounds } ...  Para llamar a un método que lanza excepciones, debe usarse try, try? o try!. Try nos permite relanzar una excepción o bien llamar al método dentro de un bloque do... catch para capturarla. try? nos permite obtener el resultado de un método que puede lanzar una excepción como un optional, u obtener nil si se produce la excepción, try! permite obtener el resultado de la ejecución del método asumiendo que éste nunca va a fallar (si se produjese una excepción se detendría la ejecución). public func sort<T : Comparable>(_ array: inout [T], fromIndex from: Int, toIndex to: Int) throws { try sort(&array, fromIndex: from, toIndex: to, comparator: { (o1, o2) -> Int in return Sorter.compare(o1, o2) }) } ... try! sorter.sort(&array, fromIndex: fromIndex, toIndex: toIndex)  Si el método devuelve void, también puede usarse do... catch{} pero se considera mala práctica no hacer nada en un bloque catch y además empeora la cobertura public func sort<T>(_ array: inout [T], comparator c: (_ o1: T, _ o2: T) -> Int) { do { try sort(&array, fromIndex: 0, toIndex: array.count, comparator: c) } catch { } }
  • 6.  En el sorter hay métodos sort que usan closures, que usan Protocols, que usan generics de tipos Comparables. En el caso de las closures y los protocols, nos permiten definir cómo se realiza la comparación entre CUALQUIER tipo de datos, y permiten incluso realizar cosas como invertir el orden de ordenado. En el caso de generics con comparables, se nos simplifica el uso de la clase, ya que no es necesario proporcionar un comparador.  En un for puede indicarse un range para indicar los valores sobre los que se iteran Sin embargo, si el valor inicial es mayor que el final, el range no puede crearse y la ejecución falla. Si se necesitase crear un range en sentido decreciente, puede hacerse con la función stride (from: to: by:) o stride(from: through: by:). En el primer caso el valor final es exclusivo y en el segundo es inclusivo. En cualquier caso, recordad que un for siempre puede expresarse como un while junto con variables sobre las que se iteran.  En el caso de FoundationSorter se nos proporcionan parámetros o1 y o2 de tipo T, que no tienen por qué ser Comparables. Podemos forzar que T sea Comparable con una función auxiliar que defina un generic como T como Comparable y haciendo el cast dentro de un if para así poder usar los operadores < y > con un tipo T. public override func sort<T>(_ array: inout [T], fromIndex: Int, toIndex: Int, comparator: (_ o1: T, _ o2: T) -> Int) { array.sort { (o1, o2) -> Bool in FoundationSorter.compare(o1, o2, Int.self) } } private static func compare<T: Comparable>(_ o1: Any, _ o2: Any, _ type: T.Type) -> Bool{ if let c1 = o1 as? T, let c2 = o2 as? T { return c1 < c2 } else { return false } }  Para poder implementar Comparators que puedan usar los operadores < y > en SwiftSorter hemos definido las siguientes clases auxiliares donde se hace un cast de un tipo T cualquiera a un tipo U comparable class ComparatorAscendant<U : Comparable> : swiftProtocolsAndGenerics.Comparator { public func compare<T>(_ o1: T, _ o2: T) -> Int { if let c1 = o1 as? U, let c2 = o2 as? U { if c1 < c2 { return -1 } else if c1 == c2 { return 0 } else { return 1 } } else { return -1 } } }
  • 7. class ComparatorDescendant<U : Comparable> : swiftProtocolsAndGenerics.Comparator { public func compare<T>(_ o1: T, _ o2: T) -> Int { if let c1 = o1 as? U, let c2 = o2 as? U { if c1 < c2 { return 1 } else if c1 == c2 { return 0 } else { return -1 } } else { return -1 } } } class ComparatorAndAveragerAscendant<U : Comparable> : swiftProtocolsAndGenerics.ComparatorAndAverager { public func compare<T>(_ o1: T, _ o2: T) -> Int { if let c1 = o1 as? U, let c2 = o2 as? U { if c1 < c2 { return -1 } else if c1 == c2 { return 0 } else { return 1 } } else { return -1 } } public func average<T>(_ o1: T, _ o2: T) -> T { if let i1 = o1 as? Int, let i2 = o2 as? Int { return ((i1 + i2) / 2) as! T } else { return 0 as! T } } }  También se han creado las clases auxiliares para el caso de Ints class IntComparatorAscendant : ComparatorAscendant<Int> { } class IntCompaaratorDescendant : ComparatorDescendant<Int> { } class IntComparatorAndAveragerAscendant : ComparatorAndAveragerAscendant<Int> { }