FERNANDO ALAVA
ndice de contenidos
Introduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Captulo 1 Presentacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.1 Objetivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.2 Portales en Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Captulo 2 Dispositivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.1 iPhone. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.2 iPad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.3 Comparativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.4 Fechas y otros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Captulo 4 Xcode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.1 Instalacin. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.2 Workspace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.3 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Captulo 7 Objective C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.1 Introduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.2 Objective C es C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7.3 Objective C aade objetos a C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7.4 Objective C aade el tipo BOOL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.5 Objective C usa las sentencias y operadores de C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.6 Vocabulario bsico de orientacin a objetos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7.7 Creacin de clases en Objective C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
7.8 Propiedades. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
7.9 Tipos y memoria. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
7.10 Creacin de objetos en Objective C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
7.11 Mtodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
7.12 Mensajes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
7.13 Referencias. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Captulo 10 MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
10.1 Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10.2 Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10.3 View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10.4 Comunicacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Captulo 12 Documentacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
12.1 Xcode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
12.2 Internet. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Captulo 13 Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
13.1 All exceptions breakpoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
13.2 Visualizar valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
13.3 Condicional breakpoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Captulo 16 Protocolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
16.1 Ayuda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Foundation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Captulo NS.1 NSLog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
NS.1.1 Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
UIKit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Captulo UI.1 UIViewController . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
UI.1.1 Ciclo de vida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Cocoapods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
Introduccin
18
Captulo 1
Presentacin
1.1 Objetivo
1.1.1 Xcode 6
Entorno de desarrollo integrado.
19
Captulo 1 Presentacin
1.1.2 Objective-C
Lenguaje de programacin orientado a objetos, ampla C.
20
Curso iOS 8
Curso iOS 8
Captulo 1 Presentacin
1.1.3 Swift
Nuevo lenguaje de programacin de Apple, compatible con Objective-C, quizs lo sustituya.
1.1.5 MVC
Estrategia para disear aplicaciones orientadas a objetos.
21
Captulo 1 Presentacin
22
Curso iOS 8
Curso iOS 8
Captulo 1 Presentacin
23
Captulo 1 Presentacin
24
Curso iOS 8
Captulo 2
Dispositivos
2.1 iPhone
Modelo
Tamao
Resolucin px
PPI
Ratio
iPhone
3.5
320x480
163
3:2
iPhone 3G
3.5
320x480
163
3:2
iPhone 3GS
3.5
320x480
163
3:2
iPhone 4
3.5
640x960
326
3:2
25
Captulo 2 Dispositivos
Curso iOS 8
iPhone 4S
3.5
640x960
326
3:2
iPhone 5
640x1136
326
16:9
iPhone 5C
640x1136
326
16:9
iPhone 5S
640x1136
326
16:9
iPhone 6
4.7
750x1334
326
16:9
iPhone 6 Plus
5.5
1080x1920
401
16:9
2.2 iPad
Modelo
Tamao
Resolucin px
PPI
Ratio
iPad
9.7
768x1024
132
4:3
iPad 2
9.7
768x1024
132
4:3
iPad Retina (3 y 4)
9.7
1536x2048
264
4:3
iPad mini
7.9
768x1024
163
4:3
iPad mini 2
7.9
1536x2048
326
4:3
iPad mini 3
7.9
1536x2048
326
4:3
iPad Air
9.7
1536x2048
264
4:3
iPad Air 2
9.7
1536x2048
264
4:3
26
Curso iOS 8
Captulo 2 Dispositivos
2.3 Comparativa
iPhone
http://www.apple.com/iphone/compare-iphones/
iPad
http://www.apple.com/ipad/compare/
iPod
http://www.apple.com/ipod/compare-ipod-models/
http://en.wikipedia.org/wiki/IPhone
iPad
http://en.wikipedia.org/wiki/IPad
MacRumors
http://buyersguide.macrumors.com/
27
28
Captulo 3
Apple Developer
3.1 Portal para desarrolladores
Sitio web para registrarse como Apple Developer e inscribirse en los programas para desarrolladores:
https://developer.apple.com/
Es el punto de entrada para acceder al Dev Center de iOS, desde donde podremos:
Acceder a la documentacin online, videos y foros
29
Curso iOS 8
3.2 Apple ID
Para para registrarse como Apple Developer es necesario crear un Apple ID, si no tenemos
ya uno.
Los Apple ID tambin se utiliza para comprar en las App Store, acceder a iCloud y muchas
otras cosas.
Para crear un nuevo Apple ID:
https://appleid.apple.com/
30
Captulo 4
Xcode
Figura 4.1 Xcode es la herramienta de Apple para desarrolladores iOS y Mac
4.1 Instalacin
Pgina de Xcode para desarrolladores (https://developer.apple.com/xcode/)
Descarga desde la Mac App Store (http://itunes.apple.com/us/app/xcode/
id497799835?ls=1&mt=12)
Descarga para desarrolladores (https://developer.apple.com/downloads/
index.action)
31
Captulo 4 Xcode
4.2 Workspace
32
Curso iOS 8
Curso iOS 8
Captulo 4 Xcode
4.2.2 Editor
El rea de edicin se puede dividir en dos o ms (mediante los botones a la derecha en la
barra de herramientas)
Hay diferentes tipos de editores:
Cdigo
Interfaz builder: Storyboards (interfaz visual)
Previsualizar (aspecto antes de lanzar el simulador)
Modelo de datos (Core Data: entidades, propiedades, relaciones)
Proyecto (propiedades, iconos, frameworks)
Assets grficos y otros
El rea de edicin arriba tiene accesos rpidos a:
Archivos relacionados
Anterior / Siguiente archivo
Cambio rpido de proyecto, carpeta, fichero y declaracin o mtodo
33
Captulo 4 Xcode
Curso iOS 8
4.2.3 Navegadores
34
Curso iOS 8
Captulo 4 Xcode
4.2.4 Depuracin
Cuando se ejecuta una app abajo tenemos una barra de herramientas:
Puntos de parada
Ejecucin paso a paso
Localizacin y otros
Y dos reas:
Inspector en tiempo de ejecucin (variables, hilos)
Logs y lldb (o gdb) para lanzar comandos de depuracin
35
Captulo 4 Xcode
Curso iOS 8
Curso iOS 8
Captulo 4 Xcode
4.3 Referencias
iOS Developer Library: Xcode_Overview (https://developer.apple.com/library/ios/
documentation/ToolsLanguages/Conceptual/Xcode_Overview/chapters/
about.html)
PDF: Xcode_Overview (/doc/Xcode_Overview.pdf)
37
38
Captulo 5
Trucos de Xcode
5.1 Referencias y videos
http://developer.apple.com/library/mac/#recipes/xcode_help-source_editor
Curso iOS 8
Curso iOS 8
Ctrl+I Reindentar
Cmd+[ Indentar
Cmd+] Desindentar
Alt+Cmd+Izq Code Folding, plegar
Alt+Cmd+Dch Code Folding, desplegar
Ctrl+1 a Ctrl+6 Acceso a items barra editor, flechas o escribir para moverse, Enter
para cambiar, Esc para cancelar
5.3.4 Simulador
Cmd+R Run
Cmd+. Stop
5.5 Plugins
5.5.1 ColorSense
https://github.com/omz/ColorSense-for-Xcode
41
42
Captulo 6
App: HolaMundo
6.1 Abrir Xcode
1. Dock
Buscar icono de Xcode (plano y martillo) y hacer click
2. Spotlight
Cmd+Space para abrirlo
43
Curso iOS 8
Buscar Xcode
Seleccionar Aplicaciones > Xcode y Enter
3. Finder
Cmd+Tab para cambiar de aplicacin
Seleccionar Finder
Ir a Aplicaciones > Xcode.app
44
Curso iOS 8
Curso iOS 8
Ir al Navegador de Proyectos (el primer icono, con una carpeta, debajo del botn
Run)
Abrir proyecto HolaMundo (click en el tringulo)
Abrir carpeta HolaMundo
Seleccionar Main.storyboard
Seleccionar los controles UIKit que necesitamos en la librera de objetos, abajo a la derecha, y arrastrar dentro de nuestro View. Se puede buscar utilizando el campo inferior (p.ej.
label).
Crear un Label y a la derecha en las opciones cambiar Text a "Hola Mundo"
Crear un Text Field y colocarlo justo debajo del Label
46
Curso iOS 8
Crear un Button (Round Rect Button), colocarlo debajo del Text Field y cambiar su
Title a "Hola"
Volver a testear en el Simulador.
Rotacin del dispositivo, comprobar lo que ocurre al girar el dispositivo con Cmd+dch
y Cmd+izq.
47
Curso iOS 8
Ahora queremos que el campo de texto y el botn hagan algo, al pulsar el botn deber
cambiar el texto de la etiqueta por el que contenga el campo de texto. Para ello necesitamos aprender ms cosas de Xcode y Objective C, el lenguaje que se utiliza para programar.
En Xcode arriba a la derecha pulsamos el segundo botn Show the Assistant editor de manera que veamos a la vez dos editores:
1. El storyboard con nuestro View seleccionado
2. El fichero .h de nuestro ViewController
En el storyboard seleccionamos el control Label y pulsando Ctrl arrastramos hasta el editor de cdigo, entre las palabras clave @interface y @end para crear un Outlet con nombre label.
Un Outlet conecta a un View (control) con la propiedad del ViewController (clase de
cdigo) que utilizaremos para manejarlo.
Hacemos lo mismo con el campo de texto y el botn y los llamaremos texto y boton (sin
acento).
Veremos que crea el siguiente cdigo Objective C en HolaMundoViewController.h:
48
Curso iOS 8
#import <UIKit/UIKit.h>
@interface HolaMundoViewController :
@property (weak, nonatomic) IBOutlet
@property (weak, nonatomic) IBOutlet
@property (weak, nonatomic) IBOutlet
@end
UIViewController
UILabel *label;
UITextField *texto;
UIButton *boton;
Ahora en el editor de la derecha, justo arriba, cambiamos de archivo y seleccionamos HolaMundoViewController.m y vamos a crear una funcin para recibir el evento de tocar
el botn.
Seleccionamos el botn Hola e igual que antes, pulsamos Ctrl y arrastramos hasta el editor de cdigo, justo bajo la palabras clave @implementation, la nombramos accionHola y
Xcode crear este cdigo:
- (IBAction)accionHola:(id)sender {
}
Esto es un mtodo de Objective C, la primera diferencia con una funcin de C es que el mtodo empieza con un guin (menos) y la segunda es que el parmetro va a continuacin
del nombre separado por dos puntos.
Teniendo en cuenta que:
self es la referencia al objeto de clase HolaMundoViewController creado por el
sistema al visualizar esta pantalla del Storyboard.
label y texto son las referencia a los objetos label y campo de texto creados en el
Storyboard y referenciados mediante el outlet.
text es la propiedad que contiene el texto actual de dichos objetos.
Finalmente aadimos una lnea de cdigo como cuerpo de la funcin.
Podramos hacer esto, como en otros lenguajes orientados a objetos:
- (IBAction)accionHola:(id)sender {
self.label.text = self.texto.text;
}
Curso iOS 8
- (IBAction)accionHola:(id)sender {
[self.label setText:[self.texto text]];
}
o
self.label.text = [self.texto text];
Curso iOS 8
- (void)viewDidLoad
{
[super viewDidLoad];
}
@end
6.6 Notas
Por ahora no hay forma de esconder el teclado, para ello hay que explicar ms cosas y lo
haremos como ejercicio un poco ms tarde.
Curso iOS 8
Hacer que al tocar return tambin cambie el texto de la etiqueta adems de esconder el
teclado.
-(void)cambiaTexto {
self.label.text = self.texto.text;
}
- (IBAction)accionHola:(id)sender {
[self cambiaTexto];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self cambiaTexto];
[texto resignFirstResponder];
return YES;
}
52
Captulo 7
Objective C
7.1 Introduccin
53
Captulo 7 Objective C
Curso iOS 8
7.2 Objective C es C
7.2.1 Comentarios // y /* */
// Comentar hasta el final de la lnea
/* Comentar un bloque */
Curso iOS 8
Captulo 7 Objective C
doble_precision);
NSLog(@"Letra %c", letra);
NSLog(@"String de C %s", texto);
NSLog(@"String de Objective C %@", nombre);
55
Captulo 7 Objective C
Curso iOS 8
Una propiedad interesante del valor nil es que se le puede enviar cualquier mensaje y
siempre devolver nil sin cascar el programa.
7.5.4 switch
int n = 3;
switch(n) {
case 1:
NSLog(@"Uno");
break;
case 2:
NSLog(@"Dos");
break;
case 3:
NSLog(@"Tres");
break;
}
Curso iOS 8
Captulo 7 Objective C
7.5.6 while
int j = 10;
while(j--) {
NSLog(@"j es %d", j);
}
7.5.7 for
for(int i = 0; i != 10; ++i) {
NSLog(@"i es %d", i);
}
57
Captulo 7 Objective C
58
Curso iOS 8
Curso iOS 8
Captulo 7 Objective C
Captulo 7 Objective C
Curso iOS 8
7.8 Propiedades
7.8.1 Declaracin de una propiedad
@property (strong, nonatomic) NSString *nombre;
Curso iOS 8
Captulo 7 Objective C
- (void)setNombre:(NSString *)nombre
{
_nombre = nombre;
}
// Getter
- (NSString *)nombre
{
return _nombre;
}
61
Captulo 7 Objective C
Curso iOS 8
7.11 Mtodos
Curso iOS 8
Captulo 7 Objective C
@implementation MyClass
- (void)miMetodoDeInstancia
{
// Cdigo
}
+ (void)miMetodoDeClase
{
// Cdigo
}
@end
7.11.1 Parmetros
En Objective C los parmetros tienen nombre y se intercalan en la declaracin:
// Sin parmetros
- (void)miMetodoSinParametros
{
// Cdigo
}
63
Captulo 7 Objective C
Curso iOS 8
El
nombre
del
mtodo
(o
selector)
es
miMetodoConNom-
bre:primerApellido:segundoApellido:
7.12 Mensajes
Tambin se puede enviar mensajes a una clase, que es una forma habitual de crear objetos.
El siguiente ejemplo enva el mensaje string a la clase NSString, que devuelve un nuevo
objeto NSString:
id myObject = [NSString string];
El tipo id indica que la variable myObject puede hacer referencia a cualquier tipo de objeto, de forma que la clase real y los mtodos que implementa no se conocen cuando se compila la aplicacin.
En este ejemplo est claro que el tipo del objeto ser NSString, as que podemos cambiarlo:
64
Curso iOS 8
Captulo 7 Objective C
Ahora es una variable NSString, de forma que el compilador nos avisar si intentamos
usar mtodos que NSString no implementa.
Observa que el tipo es realmente NSString* (con asterisco). En Objective C todas las variables que referencian objetos son punteros. El tipo id est predefinido como un tipo puntero, as que no lleva asterisco.
No se recomienda anidar ms de dos mensajes en una sola lnea, o pronto el cdigo se volver difcil de seguir.
Esto no son solo parmetros con nombre. El nombre del mtodo es realmente writeToFile:atomically:.
7.13 Referencias
http://cocoadevcentral.com/d/learn_objectivec/
Apple: Programming with Objective-C (https://developer.apple.com/library/ios/
documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/
Introduction.html)
65
66
Captulo 8
App: Cuestionario
Crear una app Cuestionario que mostrar una pregunta y la respuesta vaca.
Al pulsar sobre Ver Respuesta mostrar la respuesta.
Al pulsar sobre Siguiente Pregunta mostrar la siguiente pregunta (y la respuesta
vaca).
Preguntas:
Qu es iOS?
Qu es MVC?
Qu es Objective C?
Respuestas (atencin estn desordenadas):
Model-View-Controller Modelo-Vista-Controlador
Un superconjunto estricto de C
El Sistema Operativo de iPhone e iPad
67
8.1 Simulador
68
Curso iOS 8
Curso iOS 8
8.2 Storyboard
69
Curso iOS 8
Crear un outlet independiente para cada label y una action para cada botn
Curso iOS 8
Qu es Objective C?
Respuestas (atencin estn desordenadas):
Model-View-Controller Modelo-Vista-Controlador
Un superconjunto estricto de C
El Sistema Operativo de iPhone e iPad
Curso iOS 8
Qu es un Outlet?
Qu es un Target-Action?
Respuestas (atencin estn desordenadas):
Una propiedad del controlador que referencia a un objeto vista del Storyboard
El lenguaje tradicional de desarrollo de Apple
El IDE de desarrollo de Apple
El Kit de Interfaz de Usuario (User Interface Kit)
Un mecanismo por el que el controlador puede recibir eventos de las vistas del
Storyboard
El nuevo lenguaje de desarrollo de Apple
El patrn de diseo Modelo-Vista-Controlador (Model-View-Controller)
El Sistema Operativo de iPhone e iPad
Un paquete que agrupa componentes de iOS
Una herramienta para crear interfaces de usuario completas, incluyendo
navegacin
72
Captulo 9
Gestin de la memoria
9.1 ARC
9.1.1 Strong
El sistema se encarga de:
Liberar la memoria cuando los contadores de punteros strong llegan a 0
Adems, cualquier puntero weak automticamente se cambia a nil para evitar el
cuelgue de nuestro programa al acceder a un lugar de la memoria que ya no apunta
a un objeto.
Los punteros strong indican la propiedad del objeto:
Cuando voy a crear un objeto pienso: "este objeto es mo entonces es strong".
En caso de duda usar siempre strong.
Muchsimo cuidado con crear un objeto que solo te pertenece a ti como weak. Tras
crearlo instantaneamente desaparecer de la memoria y el puntero ser nil.
Un objeto puede pertenecer a varios otros objetos a la vez, no hay problema.
73
Curso iOS 8
Salvo este: Dos objetos no pueden pertenecerse a s mismos a la vez, esto creara un ciclo de
punteros strong y nunca podran liberarse de la memoria. Habramos causado un Leak.
Si llenamos imprudentemente la memoria con objetos que no se pueden liberar, tarde o
temprano nuestra aplicacin (y el sistema) cada vez tendr menos memoria para trabajar
y nuestra aplicacin ser terminada por el sistema.
9.1.2 Weak
Para prevenir este problema cuando un objeto no nos pertenece y sabemos que vamos a
crear un ciclo utilizamos un puntero weak.
Cuando el objeto desaparezca de la memoria nuestro puntero weak ser puesto a nil y cualquier mensaje enviado a nil devuelve 0, lo cual no causar problemas catastrficos.
Cosa que s ocurrira si enviamos un mensaje a un objeto utilizando un puntero que ya no
apunta a un objeto de ese tipo (la memoria ha sido liberada y posiblemente reutilizada para otros objetos). Nuestro programa ser terminado con una excepcin de violacin de acceso de memoria... o algo peor.
9.2.1 Retain
retain es similar a strong, pero hay que liberar la memoria manualmente.
Curso iOS 8
@autoreleasepool {
return UIApplicationMain(argc, argv, nil,
NSStringFromClass([AppDelegate class]));
}
}
9.2.2 Assign
assign es como weak, pero peor... el puntero no se establecer automticamente a nil al li-
berar la memoria. Esto puede causar un crash si despus intentamos enviar un mensaje a
ese puntero.
75
76
Captulo 10
MVC
Captulo 10 MVC
Curso iOS 8
10.1 Model
10.2 Controller
10.3 View
View o Vista: Los objetos (controles) que presentan la informacin (botones, texto, imgenes...) utilizados por el controlador para representar el modelo.
Estos objetos sern tan genricos como sea posible. Muchas veces utilizaremos los que Apple proporciona tal cual y sin cambiar nada: UIButton, UILabel, UIImageView...
Cuando estudiemos los frameworks de iOS (como UIKit o MapKit) estaremos estudiando
estos objetos y cmo se utilizan. Por ejemplo UIView, el objeto ms genrico de todos, sera
algo tan sencillo como como un rectngulo en el que dibujar y que puede contener otros.
Una vista puede contener a otras, por ejemplo UITableView es un UIScrollView que contiene celdas de tipo UITableViewCell que a su vez podrn tener texto e imgenes.
10.4 Comunicacin
Una vez que los objetos estn divididos en sus tres categoras, lo importante es definir cmo se comunican entre ellos (y cmo no deben hacerlo).
Reglas:
1. El controlador se comunica siempre con su modelo y su vista para hacer su trabajo
(atencin, esta comunicacin no es bidireccional)
Outlet: es una propiedad en el controlador que ste utiliza para comunicarse con su
vista
78
Curso iOS 8
Captulo 10 MVC
79
80
Captulo 11
App: Calculadora
Crear una app Calculadora como la siguiente:
81
Curso iOS 8
11.1 Ayuda
11.1.1 Cmo se obtiene el ttulo de un botn
Como sabemos que el control es un UIButton * lo mejor es cambiar la declaracin para
poder acceder a sus propiedades
- (IBAction)pressDigito:(id)sender
- (IBAction)pressDigito:(UIButton *)sender
{
NSString *digito = sender.currentTitle;
}
82
Curso iOS 8
11.1.4 NSMutableString
Cmo se declara un string mutable?
@property (strong, nonatomic) NSMutableString *display;
Cmo se inicializa?
self.display = [NSMutableString stringWithCapacity:20];
(NSString *)displayValor;
(void) inputDigito:(NSString *)digito;
(void) inputOperador:(NSString *)operador;
(void) inputIgual;
(void) inputBorrar;
Curso iOS 8
Curso iOS 8
Realizar las conexiones necesarias entre la pantalla del StoryBoard y el archivo ViewController.
Implementar las funciones del modelo que ahora estn vacas para poder gestionar:
El nmero que debe aparecer en el display y la funcin para devolverlo
Las diferentes operaciones de entrada de datos
85
86
Captulo 12
Documentacin
12.1 Xcode
12.1.1 Quick Help
Situar el cursor sobre una palabra con el panel Quick Help seleccionado
87
Captulo 12 Documentacin
Curso iOS 8
12.2 Internet
88
Captulo 13
Debugger
13.1 All exceptions breakpoint
Cuidado porque no se puede utilizar dot notation en el depurador, hay que utilizar el mensaje get.
Print object description
(lldb) po [self nombrePropiedad]
89
Captulo 13 Debugger
90
Curso iOS 8
Captulo 14
App: Cartas
14.1 Storyboard
91
Curso iOS 8
14.3 Modelo
14.3.1 Tarea 1
Copiar las clases de las Lecture 1 y 2 de Stanford:
Card
Deck
PlayingCard
PlayingCardDeck
14.4 Controlador
14.4.1 Tarea 2
Usando los recursos grficos crear un botn que simula una carta.
14.4.2 Tarea 3
Tocando la carta alternar entre la parte anterior y posterior.
14.4.3 Tarea 4
Crear una propiedad deck de tipo Deck *
Inicializarla con una baraja completa PlayingCardDeck
Tocando la carta pasar por todas las cartas de la baraja (sin repetir ninguna)
92
Curso iOS 8
14.4.4 Tarea 5
Desarrollar el juego de cartas de la Lecture 3 de Stanford:
Situar 12 cartas en el storyboard
Copiar la clase CardMatchingGame y modificar el controlador
14.4.5 Tarea 6
Modificar el juego para:
16 cartas
Solo cartas A, J, Q y K
Solo emparejar por mismo color y figura
93
Curso iOS 8
14.4.6 Tarea 7
Modificar el juego con un botn nuevo que reinicia la puntuacin a 0 y reparte nuevas
cartas.
14.4.7 Tarea 8
Aadir un label que indique:
El valor de las cartas: A de corazones y K de corazones
El resultado de la ltima correspondencia: Coincidencia de palo
Los puntos otorgados: 4 puntos o 2 puntos de penalizacin
14.4.8 Tarea 9
Modificar el juego para emparejar todos los A, J, Q o K a la vez (los cuatro palos).
14.5 Ayuda
@property (strong, nonatomic) Deck *deck;
- (Deck *)deck
{
if (!_deck) _deck = [self createDeck];
return _deck;
}
- (Deck *)createDeck
{
return [[PlayingCardDeck alloc] init];
}
94
Captulo 15
Paths y URLs
15.1 Path
Curso iOS 8
NSString *cachePath =
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask, YES) lastObject];
NSLog(@"path: %@", cachePath);
15.2 URLs
96
Curso iOS 8
Para aadir un componente a un FileURL utilizamos el mensaje URLByAppendingPathComponent sobre otro FileURL:
NSURL *cacheMini = [cache URLByAppendingPathComponent:@"mini"
isDirectory:YES];
Para aadir un componente a un path utilizamos el mensaje stringByAppendingPathComponent sobre otro path (de tipo NSString):
NSString *cachePathMini = [cachePath
stringByAppendingPathComponent:@"mini"];
Para recomponer una URL usando algunos de los componentes de otra podemos utilizar
el mensaje stringWithFormat:
NSArray *components = [foto pathComponents];
NSString *fotoGrandeFilename = [NSString stringWithFormat:@"%@_%@_%@",
components[1], components[2], @"4.jpg";
Para comprobar si existe un fichero o directorio utilizamos el mensaje fileExistsAtPath que requiere un path:
if([[NSFileManager defaultManager] fileExistsAtPath:[cache path]]) {
// cdigo si existe el directorio o fichero
}
Curso iOS 8
98
Captulo 16
Protocolos
16.1 Ayuda
2 Crear una propiedad para recibir un delegate que cumpla nuestro protocolo
@property (weak, nonatomic) id <EditarViewControllerDelegate> delegate;
99
Captulo 16 Protocolos
Curso iOS 8
#import "EditarViewController.h"
@interface ListadoViewController : UITableViewController
<EditarViewControllerDelegate>
@end
2 Implementar el protocolo
-(void)guardarCerveza:(Cerveza *)cerveza
{
[self.cervezas guardarCerveza:cerveza];
[self.navigationController popToRootViewControllerAnimated:YES];
[self.tableView reloadData];
}
100
Captulo 17
App: Cervezas
17.1 Objetivo
Desarrollaremos una app para iPhone para comprobar nuestros conocimientos actuales
sobre desarrollo para iOS.
Los recursos necesarios estn en Cervezas.zip (/descargas/Cervezas.zip)
Versiones del profesor:
Cervezas1.zip (/descargas/Cervezas/Cervezas1.zip)
Cervezas2.zip (/descargas/Cervezas/Cervezas2.zip)
101
Curso iOS 8
17.2 Storyboard
17.3 Modelo
Crearemos una clase Cervezas encargada de leer los datos de la property list
beers.plist y aadirlos a un array.
Crearemos otra clase Cerveza para encapsular los datos de una cerveza adems de un
identificador que ser la posicin en el array.
Esta clase deber tener un inicializador que reciba: id, nombre, tipo y foto.
17.4 Listado
Curso iOS 8
17.5 Detalle
Al tocar en una fila mostraremos una pantalla de detalle, con los mismos datos.
El nico parmetro que pasaremos al detalle ser un objeto de tipo Cerveza.
103
17.6 Edicin
104
Curso iOS 8
Curso iOS 8
Pondremos dos botones en la pantalla Listado Aadir y Editar que irn a la pantalla de
Edicin mediante dos Segues.
La tabla tendr dos modos: normal y edicin que se cambiar pulsando el botn Edicin.
Pista:
self.navigationItem.leftBarButtonItem = self.editButtonItem;
Y las celdas estarn preconfiguradas para mostrar o no el botn azul de edicin segn el
modo. Pista:
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.editingAccessoryType =
UITableViewCellAccessoryDetailDisclosureButton;
105
Curso iOS 8
El nico parmetro que pasaremos al detalle ser un objeto de tipo Cerveza (existente o
bien nuevo pero ya con su futuro id).
Deberemos crear un protocolo en la pantalla de Edicin que ser implementado por la
pantalla Listado para ser avisada de la modificacin de los datos de una Cerveza.
17.7 Protocolos
Curso iOS 8
2 Crear una propiedad para recibir un delegate que cumpla nuestro protocolo
@property (weak, nonatomic) id <EditarViewControllerDelegate> delegate;
2 Implementar el protocolo
-(void)guardarCerveza:(Cerveza *)cerveza
{
[self.cervezas guardarCerveza:cerveza];
[self.navigationController popToRootViewControllerAnimated:YES];
[self.tableView reloadData];
}
Curso iOS 8
17.8 Persistencia
Cada vez que se modifique una Cerveza, la clase Cervezas se encargar de guardarla en
el sistema de ficheros.
Aprenderemos a utilizar un Picker para poder seleccionar una foto entre todas las disponibles.
Crearemos una nueva pantalla con un picker con la lista de imgenes diponibles, una imagen para ver la actualmente seleccionada y dos botones Aceptar y Cancelar.
Deberemos crear un protocolo en la pantalla de Seleccin de Foto que ser implementado
por la pantalla Edicin para ser avisada de la seleccin (o no) de una nueva foto.
108
Curso iOS 8
17.10 Ayuda
17.10.1 Cervezas.h
#import <Foundation/Foundation.h>
#import "Cerveza.h"
@interface Cervezas : NSObject
@property (strong, nonatomic) NSString *path;
@property (strong, nonatomic) NSMutableDictionary *cervezas;
@property (strong, nonatomic) NSMutableArray *fotos;
+ (Cervezas *)sharedInstance;
- (Cerveza *)cervezaConIdentificador:(NSInteger)identificador;
- (Cerveza *)cervezaConIndex:(NSInteger)index;
- (void)guardarCerveza:(Cerveza *)cerveza;
- (void)borrarCervezaConIdentificador:(NSInteger)identificador;
@end
17.10.2 Cervezas.m
#import "Cervezas.h"
@implementation Cervezas
+ (Cervezas *)sharedInstance
{
static Cervezas *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[Cervezas alloc] init];
});
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
// Obtener la lista de directorios que corresponden a mi bsqueda
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
// El path a Documentos es el primero (solo habr un elemento en
el array)
NSString *docsDir = [paths objectAtIndex:0];
109
Curso iOS 8
Curso iOS 8
}
- (void)archivarDatos
{
//[_cervezas writeToFile:_path atomically:YES];
[NSKeyedArchiver archiveRootObject:_cervezas toFile:_path];
}
-(Cerveza *)cervezaConIdentificador:(NSInteger)identificador
{
return [self.cervezas valueForKey:[NSString stringWithFormat:@"%i",
identificador]];
}
-(Cerveza *)cervezaConIndex:(NSInteger)index
{
NSArray *claves = [self.cervezas allKeys];
/*NSArray *claves = [[self.cervezas allKeys]
sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];*/
/*NSArray *claves = [[self.cervezas allKeys]
sortedArrayUsingComparator:^(NSString *claveA, NSString *claveB) {
Cerveza *cervezaA = [self.cervezas valueForKey:claveA];
Cerveza *cervezaB = [self.cervezas valueForKey:claveB];
return [cervezaA.nombre caseInsensitiveCompare:cervezaB.nombre];
}];*/
NSString *clave = [claves objectAtIndex:index];
return [self.cervezas objectForKey:clave];
}
-(void)guardarCerveza:(Cerveza *)cerveza
{
[self.cervezas setValue:cerveza forKey:[NSString
stringWithFormat:@"%i", cerveza.identificador]];
[self archivarDatos];
}
-(void)borrarCervezaConIdentificador:(NSInteger)identificador
{
[self.cervezas removeObjectForKey:[NSString stringWithFormat:@"%i",
identificador]];
[self archivarDatos];
}
@end
17.10.3 Cerveza.h
#import <Foundation/Foundation.h>
@interface Cerveza : NSObject <NSCoding>
@property (nonatomic) NSUInteger identificador;
@property (strong, nonatomic) NSString *nombre;
111
Curso iOS 8
17.10.3.1 Cerveza.m
#import "Cerveza.h"
@implementation Cerveza
-(Cerveza *)initWithIdentificador:(NSUInteger)identificador
nombre:(NSString *)nombre
tipo:(NSString *)tipo
foto:(NSString *)foto
{
self = [super init];
if (self) {
_identificador = identificador;
_nombre = nombre;
_tipo = tipo;
_foto = foto;
}
return self;
}
-(NSString *)description
{
return [NSString stringWithFormat:@"%i %@", self.identificador,
self.nombre];
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
_identificador = [aDecoder decodeIntegerForKey:@"identificador"];
_nombre = [aDecoder decodeObjectForKey:@"nombre"];
_tipo = [aDecoder decodeObjectForKey:@"tipo"];
_foto = [aDecoder decodeObjectForKey:@"foto"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeInteger:self.identificador forKey:@"identificador"];
[aCoder encodeObject:self.nombre forKey:@"nombre"];
[aCoder encodeObject:self.tipo forKey:@"tipo"];
112
Curso iOS 8
113
114
Captulo 18
Persistencia
Cmo guardar informacin entre lanzamientos de la aplicacin?
18.1 NSUserDefaults
El primer mecanismo ya lo conocemos: NSUserDefaults, pero se debe usar solo para pequeas piezas de informacin
18.3 Archivado
Captulo 18 Persistencia
Curso iOS 8
18.4 NSKeyed[Un]Archiver
Estas clases se usan para guardar/recuperar el rbol. Se realiza contra objetos NSData.
NSKeyedArchiver guarda el objeto en un NSData:
+ (NSData *)archivedDataWithRootObject:(id <NSCoder>)rootObject;
Nuestras aplicaciones den el sistema de archivos de iOS como uno de Unix. Empieza en /
(raiz/root)
Hay permisos de archivos, igual que en Unix, as que no es posible ver todo.
Solo podemos escribir dentro del sandbox
116
Curso iOS 8
Captulo 18 Persistencia
Devuelve un NSArray de paths. Normalmente solo hay un path en el array en iOS. Porque
no hay directorio home, compartidos del sistema, etc.
Seguramente usaremos lastObject (por simplicidad).
Ejemplos de valores de NSSearchPathDirectory: NSDocumentsDirectory, NSCachesDirectory, NSAutosavedInformationDirectory, etc.
18.6 NSFileManager
Proporciona operaciones auxiliares sobre el sistema de archivos (porque la lectura y escritura se hace con NSData y otros):
Chequear si un archivo existe
Crear y enumerar directorios
Mover, copiar y borrar archivos
117
Captulo 18 Persistencia
Curso iOS 8
Tiene un protocolo para enviar a su delegate mtodos should... para consultas y recuperacin de errores. Ver documentacin.
18.7 NSString
18.8 SQLite
118
Curso iOS 8
Captulo 18 Persistencia
18.8.1 API
int sqlite3_open(const char *filename, sqlite3 **db); // get a database
into db
int sqlite3_exec(sqlite3 *db, // execute SQL statements
const char *sql,
int (*callback)(void *, int, char **, char **),
void *context,
char **error);
int mycallback(void *context, int count, char **values, char **cols); //
data returned
int sqlite3_close(sqlite3 *db); // close the database
Se trata del mecansmo ms avanzado. Una capa de orientacin a objetos por encima de
SQLite (y otras posibilidades de persistencia).
Nos permite definir las clases y propiedades, gestionar las relaciones y persistir un rbol
de objetos.
Y lo veremos un poco ms adelante.
119
120
Captulo 19
App: Libros
En este proyecto deberis crear una aplicacin que permita guardar informacin sobre libros.
Crear una clase Libro para guardar los datos de cada libro:
Ttulo
Autor
Foto
La clase Libro deber tener un mtodo init (inicializador) que acepte los tres datos como
parmetros:
- initConTitulo:Autor:Foto:
121
Curso iOS 8
Crear una clase Libros con una propiedad array o diccionario para almacenar todos los
libros.
La clase Libros deber tener un mtodo init (inicializador) que lea el archivo libros.plist y
aada cada libro como un objeto de clase Libro.
Crear una pantalla de tipo UITableViewController para mostrar el listado de libros con
los siguientes datos:
Ttulo
Autor
Foto
Implementar los mtodos necesarios del protocolo datasource para visualizar el listado de
libros.
Crear una transicin show desde la pantalla del listado hasta la pantalla de detalle.
Implementar el mtodo prepareForSegue y enviar desde la pantalla del listado a la pantalla de detalle el objeto libro seleccionado.
122
Curso iOS 8
Deber ser posible regresar a la pantalla del listado utilizando el botn back del controlador de navegacin.
Crear una pantalla para editar o aadir los datos de un libro con campos de texto para:
Ttulo
Autor
Foto
Adems de un botn guardar.
Crear dos transiciones show desde la pantalla del listado hasta la pantalla de detalle:
Transicin Editar desde la celda de la tabla
Transicin Nuevo desde el botn Nuevo
Implementar el mtodo prepareForSegue y enviar desde la pantalla del listado a la pantalla de detalle el objeto libro seleccionado o uno vaco en caso del botn Nuevo.
Curso iOS 8
Hacer que la clase libro sea archivable implementando el protocolo NSCoding y los mtodos:
initWithCoder
encodeWithCoder
Obtener una ruta al sandbox para poder archivar los datos de los libros.
Si existe el fichero con los datos archivados leer de ah los datos de los libros
Si no existe el fichero con los datos archivados leer los datos del property list y
despus archivarlos ah
124
Captulo 20
Blocks
20.1 Referencias
20.2 Qu es un block?
Captulo 20 Blocks
Curso iOS 8
20.5 Enumerar
-(void)buscarCervezaPorNombre:(NSString *)nombre
{
__block BOOL existe = NO;
[self.cervezas enumerateObjectsUsingBlock:
^(NSDictionary *cerveza, NSUInteger idx, BOOL *stop) {
NSString *nombreCerveza =
[cerveza valueForKey:@"name"];
NSLog(@"Cerveza %i: %@", idx, nombreCerveza);
if ([nombreCerveza isEqualToString:nombre]) {
existe = YES;
*stop = YES;
}
}
];
if(existe) NSLog(@"Existe %@", nombre);
else NSLog(@"No existe %@", nombre);
}
20.6 Ordenar
[self.cervezas sortUsingComparator:
^(NSDictionary *cerveza1, NSDictionary *cerveza2) {
NSString *nombreCerveza1 = [cerveza1 valueForKey:@"name"];
NSString *nombreCerveza2 = [cerveza2 valueForKey:@"name"];
return [nombreCerveza1 compare:nombreCerveza2
options:NSCaseInsensitiveSearch];
}
];
20.7 Animar
-(void)animacion
{
self.tableView.alpha = 0.0;
[UIView animateWithDuration:2.0 animations:^{
self.tableView.alpha = 1.0;
}];
}
Curso iOS 8
Captulo 20 Blocks
} completion:^(BOOL finished) {
if(finished) {
UIAlertView *alerta =
[[UIAlertView alloc]
initWithTitle:@"Animacin"
message:@"Completada"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alerta show];
}
}];
}
127
128
Captulo 21
Todas las tareas que consuman demasiado tiempo (descargar datos de Internet) deberamos pasarlos segn su prioridad a una de las colas globales para liberar la cola principal
(main_queue), responsable de todas las tareas del UI (Interfaz de Usuario).
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),
^{
// cdigo...
}
);
129
Curso iOS 8
Curso iOS 8
data
completion(data);
});
});
}
131
132
Captulo 22
La primera tarea sera definir qu Entidades, Atributos y Relaciones tenemos entre las
Clases que formarn nuestro rbol de objetos.
Para ello crearemos una carpeta Modelo en la que guardaremos todos los archivos que lo
componen.
133
Curso iOS 8
134
Curso iOS 8
135
Curso iOS 8
Se denomina pila o stack de Core Data a los todos objetos que tenemos que crear y configurar para que Core Data pueda funcionar normalmente.
136
Curso iOS 8
Esta es la parte complicada de aprender Core Data ya que son necesarios varios objetos
nuevos que tenemos que ir desgranando y cada uno tiene sus propias responsabilidades
que tenemos que aprender.
Una vez hemos decidido utilizar Core Data para gestionar nuestro modelo debemos incluir su Framework en nuestro proyecto de Xcode.
137
Curso iOS 8
Al compilar nuestro proyecto, el esquema grfico ser compilado en un objeto de tipo NSManagedObjectModel que lo soportar mediante un cdigo del que no nos tendremos que
preocupar.
138
Curso iOS 8
139
Curso iOS 8
Tanto si nuestra aplicacin soporta documentos de usuario como si no, podemos crear un
UIManagedDocument para facilitarnos la vida y trabajar con Core Data.
Crear un UIManagedDocument:
UIManagedDocument *document = [[UIManagedDocument alloc]
initWithFileURL:(URL *)url];
Si existe abrirlo:
- (void)openWithCompletionHandler:(void (^)(BOOL
success))completionHandler;
Si no existe crearlo:
- (void)saveToURL:(NSURL *)url
forSaveOperation:(UIDocumentSaveOperation)operation
competionHandler:(void (^)(BOOL success))completionHandler;
140
Curso iOS 8
Una vez abierto podemos usarlo, pero est bien comprobar su documentState:
- (void)documentIsReady
{
if (self.document.documentState == UIDocumentStateNormal) {
NSManagedObjectContext *context =
self.document.managedObjectContext;
// Seguir operando con el contexto de Core Data
}
}
Otros documentStates:
UIDocumentStateClosed: cerrado o no existe
UIDocumentStateSavingError: xito == NO
UIDocumentStateEditingDisabled: temporalmente deshabilitado
UIDocumentStateInConflict: con conflicto, p.ej. modificado desde iCloud
Guardar un documento, como abrirlo o crearlo, tambin se hace asncronamente.
Los documentos se guardan automticamente pero est bien guardarlos manualmente.
Para hacerlo se usa el msmo mtodo que en la creacin pero con diferente forSaveOperation:
141
Curso iOS 8
[self.document saveToURL:self.document.fileURL
forSaveOperation:UIDocumentSaveForOverwriting
completionHandler:^(BOOL success) {
if (!success) {
NSLog(@"failed to save document %@",
self.document.localizedName);
}
}
}];
// Aqu todava no se ha guardado, usar completion
Propiedades de UIManagedDocument:
@property (nonatomic, strong) NSURL *fileURL; // usada en initWithFileURL
@property (readonly) NSString *localizedName; // solo vlido si est
asociado a un fichero
Cerrar un documento tambin es una operacin asncrona. Aunque el documento tambin se cerrar si no hay punteros strong hacia ste.
Para cerrarlo manualmente:
[self.document closeWithCompletionHandler:^(BOOL success) {
if (!success) NSLog(@"failed to close document %@",
self.document.localizedName);
}];
// the document is not closed at this point in the code (only once the
block above executes)
22.9 Consultas
Curso iOS 8
Qu Entidad/clase? Obligatorio
Qu Entidades/objetos? NSPredicate predicado que indica qu entidades obtener
y cules no. Opcional, por defecto todas.
En qu orden? NSSortDescriptors: objeto que indica el orden
Cuntos objetos cada vez y/o mximo nmero? Opcional
Ejemplo:
NSFetchRequest *request = [NSFetchRequest
fetchRequestWithEntityName:@"Foto"];
request.fetchBatchSize = 20;
request.fetchLimit = 100;
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
request.predicate = ...;
22.9.1 NSPredicate
Formatos:
NSString *serverName = @"flickr-5";
NSPredicate *predicate =
[NSPredicate predicateWithFormat:@"thumbnailURL contains %@",
serverName];
Ejemplos:
@"id = %@", [flickrInfo objectForKey:@"id"] // identificador = algo que
le pasemos
@"visto > %@", (NSDate *) // visto es una fecha
@"autor.nombre = %@", (NSString *) // Bsca fotos por nombre de autor
(devuelve fotos)
@"any fotos.descripcion contains %@", (NSString *) // Busca fotgrafo
cuyas fotos contienen texto (LIKE)
22.9.2 NSSortDescriptor
Al hacer una consulta retornar un NSArray de NSManagedObjects. El NSArray estar
ordenado, lo indicamos nosotros
NSSortDescriptor *sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:@"url_grande"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)];
143
Curso iOS 8
22.9.4 Faulting
Los objetos managed se van a buscar a la base de datos cuando se solicitan:
for (Fotografo *fotografo in fotografos) {
NSLog(@fetched fotografo %@, fotografo);
}
for (Fotografo *fotografo in fotografos) {
NSLog(@fetched fotografo nombre %@, fotografo.name);
}
Curso iOS 8
Curso iOS 8
146
Captulo 23
Para comprobar las consultas SQL que se estn ejecutando es interesante activar la depuracin CoreData SQLDebug
Ir al la barra de Xcode y a la derecha del Stop, pinchar en nombre app (en este caso Core
Data) para editar el esquema: Product > Edit Scheme
147
Curso iOS 8
23.2 ViewController.h
#import <UIKit/UIKit.h>
#import "Foto+Metodos.h"
#import "Fotografo+Metodos.h"
@interface ViewController : UIViewController <UITableViewDataSource,
UITableViewDelegate, NSFetchedResultsControllerDelegate>
@property (strong, nonatomic) UIManagedDocument *FotoDB;
@property (strong, nonatomic) NSFetchedResultsController
*fetchedResultsController;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
23.3 ViewController.m
#import "ViewController.h"
@implementation ViewController
148
Curso iOS 8
- (void)setup
{
if (!self.FotoDB) {
NSURL *url = [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
lastObject];
url = [url URLByAppendingPathComponent:@"FotoDB"];
self.FotoDB = [[UIManagedDocument alloc] initWithFileURL:url];
}
}
- (void)setFotoDB:(UIManagedDocument *)FotoDB
{
if (_FotoDB != FotoDB) {
_FotoDB = FotoDB;
[self usarDocumento];
}
}
- (void)usarDocumento
{
if (![[NSFileManager defaultManager]
fileExistsAtPath:[self.FotoDB.fileURL path]]) {
[self.FotoDB saveToURL:self.FotoDB.fileURL
forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL
success) {
// Cargar datos en FotoDB...
NSLog(@"Cargar datos en FotoDB...");
[self cargarDatosEnFotoDB];
[self consultarDatosEnFotoDB];
}];
} else if (self.FotoDB.documentState == UIDocumentStateClosed) {
// Existe y hay que abrirlo
[self.FotoDB openWithCompletionHandler:^(BOOL success) {
// El documento est abierto, hacer consultas...
NSLog(@"El documento est abierto, hacer consultas...");
[self cargarDatosEnFotoDB];
[self consultarDatosEnFotoDB];
}];
} else if (self.FotoDB.documentState == UIDocumentStateNormal) {
// El documento ya est abierto, hacer consultas...
NSLog(@"El documento ya est abierto, hacer consultas...");
}
}
149
Curso iOS 8
- (void)cargarDatosEnFotoDB
{
NSManagedObjectContext *contexto = self.FotoDB.managedObjectContext;
Fotografo *fotografo1 = [Fotografo crearFotografoConDatos:@{
@"nombre" : @"Fotografo1" } contexto:contexto];
Foto *foto1 = [Foto crearFotoConDatos:@{ @"descripcion" : @"Foto1" }
contexto:contexto];
Foto *foto2 = [Foto crearFotoConDatos:@{ @"descripcion" : @"Foto2" }
contexto:contexto];
Foto *foto3 = [Foto crearFotoConDatos:@{ @"descripcion" : @"Foto3" }
contexto:contexto];
NSSet *fotos = [NSSet setWithArray:@[foto1, foto2, foto3]];
[fotografo1 addFotos:fotos];
Fotografo *fotografo2 = [Fotografo crearFotografoConDatos:@{
@"nombre" : @"Fotografo2" } contexto:contexto];
Foto *foto21 = [Foto crearFotoConDatos:@{ @"descripcion" : @"Foto21"
} contexto:contexto];
foto21.autor = fotografo2;
}
- (void)consultarDatosEnFotoDB
{
[self consultarTodasLasFotos];
[self consultarTodosLosFotografos];
}
- (void)consultarTodasLasFotos
{
NSManagedObjectContext *contexto = self.FotoDB.managedObjectContext;
NSFetchRequest *request = [NSFetchRequest
fetchRequestWithEntityName:@"Foto"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor
sortDescriptorWithKey:@"descripcion" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *fotos = [contexto executeFetchRequest:request error:&error];
NSLog(@"Todas las fotos: %@", fotos);
}
150
Curso iOS 8
- (void)consultarTodosLosFotografos
{
NSManagedObjectContext *contexto = self.FotoDB.managedObjectContext;
NSFetchRequest *request = [NSFetchRequest
fetchRequestWithEntityName:@"Fotografo"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor
sortDescriptorWithKey:@"nombre" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *fotografos = [contexto executeFetchRequest:request
error:&error];
NSLog(@"Todos los fotografos: %@", fotografos);
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setup];
}
@end
23.4 Foto+Metodos.h
#import "Foto.h"
@interface Foto (Metodos)
+ (Foto *)crearFotoConDatos:(NSDictionary *)datos
contexto:(NSManagedObjectContext *)contexto;
@end
23.5 Foto+Metodos.m
#import "Foto+Metodos.h"
@implementation Foto (Metodos)
+ (Foto *)crearFotoConDatos:(NSDictionary *)datos
contexto:(NSManagedObjectContext *)contexto
{
Foto *foto = nil;
NSString *descripcion = [datos valueForKey:@"descripcion"];
151
Curso iOS 8
23.6 Fotografo+Metodos.h
#import "Fotografo.h"
@interface Fotografo (Metodos)
+ (Fotografo *)crearFotografoConDatos:(NSDictionary *)datos
contexto:(NSManagedObjectContext *)contexto;
@end
152
Curso iOS 8
23.7 Fotografo+Metodos.m
#import "Fotografo+Metodos.h"
@implementation Fotografo (Metodos)
+ (Fotografo *)crearFotografoConDatos:(NSDictionary *)datos
contexto:(NSManagedObjectContext *)contexto
{
Fotografo *fotografo = nil;
NSString *nombre = [datos valueForKey:@"nombre"];
NSFetchRequest *request = [NSFetchRequest
fetchRequestWithEntityName:@"Fotografo"];
request.predicate = [NSPredicate predicateWithFormat:@"nombre = %@",
nombre];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor
sortDescriptorWithKey:@"nombre" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *fotografos = [contexto executeFetchRequest:request
error:&error];
if (fotografos == nil) {
// error, el array fotografos es nil
} else if ([fotografos count] > 1) {
// error, solo debera haber un resultado
// y nombre no es un identificador nico
} else if([fotografos count] == 0) {
// si el array est vaco, el fotografo no est en la BD y hay
que meterlo
fotografo = [NSEntityDescription
insertNewObjectForEntityForName:@"Fotografo"
inManagedObjectContext:contexto];
fotografo.nombre = nombre;
} else if([fotografos count] == 1) {
// si el array tiene un elemento, devolvemos ese fotgrafo
// aqu podramos decidir cambiar algn dato
fotografo = [fotografos lastObject];
}
return fotografo;
}
153
@end
154
Curso iOS 8
Captulo 24
NSFetchedResultsController
Se trata de un controlador especialmente pensado para trabajar con Core Data y un TableView.
Bsicamente encapsula una consulta NSFetchRequest y reduce el cdigo necesario para
visualizar el TableView.
Pero adems est atento a todos los cambios en el contexto managedObjectContext y los
enva como eventos a su delegado para actuar sobre la tabla y crear, modificar y eliminar
celdas.
Lo primero que tenemos que hacer es crear el controlador y lo asociamos a la consulta que
deseemos mostrar.
Captulo 24 NSFetchedResultsController
Curso iOS 8
Curso iOS 8
Captulo 24 NSFetchedResultsController
Captulo 24 NSFetchedResultsController
Curso iOS 8
self.fetchedResultsController.delegate = self;
}
24.3.1 controllerWillChangeContent:
Este evento nos avisa de que van a comenzar los cambios en la tabla.
-(void)controllerWillChangeContent:(NSFetchedResultsController
*)controller
{
[self.tableView beginUpdates];
}
24.3.2 controllerDidChangeContent:
Este evento nos avisa de que han terminado los cambios en la tabla.
-(void)controllerDidChangeContent:(NSFetchedResultsController
*)controller
{
[self.tableView endUpdates];
}
24.3.3 controller:didChangeSection:
Este evento nos avisa de que
-(void)controller:(NSFetchedResultsController *)controller
didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type
{
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:sectionIndex];
switch (type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:indexSet
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:indexSet
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
158
Curso iOS 8
Captulo 24 NSFetchedResultsController
24.3.4 controller:didChangeObject:
-(void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath
*)newIndexPath
{
NSArray *objetoNuevo = nil;
if(newIndexPath) objetoNuevo = [NSArray
arrayWithObject:newIndexPath];
NSArray *objetoViejo = nil;
if(indexPath) objetoViejo = [NSArray arrayWithObject:indexPath];
switch (type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:objetoNuevo
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:objetoViejo
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
{
UITableViewCell *celda = [self.tableView
cellForRowAtIndexPath:indexPath];
Foto *foto = [self.fetchedResultsController
objectAtIndexPath:indexPath];
celda.textLabel.text = foto.descripcion;
break;
}
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:objetoViejo
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:objetoNuevo
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
159
160
Captulo 25
iCloud
25.1 Introduccin
161
Captulo 25 iCloud
Curso iOS 8
25.2 Coordinacin
Los diferentes dispositivos se coordinan mediante varios NSFilePresenters (un protocolo) usando la clase NSFileCoordinator.
Nuestro UIManagedDocument es un NSFilePresenter perfecto para usarlo con iCloud
(implementa ese protocolo).
Es necesario suscribirse a las notificaciones que nos indican los cambios en iCloud.
Para poner un UIManagedDocument primero necesitamos la URL en la que vamos a guardarlo:
iCloudDocumentsURL = [iCloudURL
URLByAppendingPathComponent:@"Documents"];
162
Curso iOS 8
Captulo 25 iCloud
Pero adems, solo deberamos sincronizar los cambios de los UIManagedDocument. Usando Core Data podemos disponer de un log de estos cambios.
Para ello introducimos estas claves en el diccionario de opciones del documento persistentStoreOptions, pero siempre antes de crearlo o abrirlo:
NSPersistentStoreUbiquitousContentNameKey: el nombre del documento
NSPersistentStoreUbiquitousContentURLKey: directorio para guardar todos
los logs de cambios
Este directorio que usaremos para los logs NO debe estar en el directorio Documents de
iCloud, pero s puede ser el mismo para todos los documentos:
iCloudLogsURL = [iCloudURL URLByAppendingPathComponent:@"CoreData"];
Debemos crear una consulta que se actualizar automticamente y observar los cambios
que nos enviar mediante el sistema de notificaciones.
163
Captulo 25 iCloud
Curso iOS 8
Actualizacin de resultados:
[center addObserver:self
selector:@selector(processQueryResults:)
name:NSMetadataQueryDidUpdateNotification
object:query];
Muy importante otra vez. Antes de ser eliminados de la memoria (dealloc), desuscribirse
como observador de cualquier notificacin.
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Curso iOS 8
Captulo 25 iCloud
Captulo 25 iCloud
Curso iOS 8
25.5.1 InConflict
Si dos dispositivos tienen versiones distintas de un documento en iCloud:
Podremos comparar varias versiones
Aplicar manualmente los cambios de una a otra (quizs preguntando al usuario)
Cambiar de estado a esas versiones (ya no estn en conflicto)
Y finalmente elminar las versiones que ahora estn duplicadas
25.5.2 EditingDisabled
En este estado no podremos aplicar cambios.
25.5.3 SavingError
Avisar al usuario o intentar guardar ms tarde: conflicto? problemas de red?
Podemos cambiar las opciones de un documento de compartido en iCloud a no compartido, pero siempre fuera del hilo main
166
Curso iOS 8
Captulo 25 iCloud
Adems de usar iCloud para compartir los documentos de un usuario entre sus dispositivos. Tambin es posible exportar una URL temporal para compartir un fichero entre
usuarios distintos. Pero solo ficheros no directorios. La URL apunta a la copia de este fichero (que es solo de lectura)
NSURL *urlToShare = @"...";
NSDate *date;
NSError *error;
NSURL *sharedURL =
[[NSFileManager defaultManager]
URLForPublishingUbiquitousItemAtURL:urlToShare
expirationDate:&date
error:&error];
25.8 NSUbiquitousKeyValueStore
Como NSUserDefaults, pero en iCloud
25.8.3 Notificaciones
Como los datos pueden cambiar en cualquier momento hay que suscribirse a sus notificaciones:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(ubiquitousKeyValueStoreChanged:)
name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
object:[NSUbiquitousKeyValueStore defaultStore]];
167
Captulo 25 iCloud
Curso iOS 8
168
Captulo 26
Servicios Web
Prcticamente cualquier aplicacin que desarrollemos deber conectarse en algn momento con un servicio web.
Para ello deberemos utilizar alguno de los protocolo de comunicaciones que estos servicios web implementen, p.ej:
SOAP/WSDL
REST basado en XML o JSON
SDKs oficiales (o de terceros)
26.1 SOAP/WSDL
Es un protocolo antiguo basado en HTTP para el transporte y XML para los contenidos de
las llamadas. Se ha usado bastante en el mundo de Java y C# .NET.
Wikipedia: SOAP (http://es.wikipedia.org/wiki/SOAP)
Wikipedia: WSDL (http://es.wikipedia.org/wiki/WSDL)
No tenemos soporte directo en el iOS SDK, as que en principio deberamos construir
nuestras consultas manualmente utilizando la infraestructura bsica que proporcionan
NSURLRequest y NSXMLParser.
Aunque nuestra mejor opcin aqu es utilizar una herramienta de generacin de cdigo:
wsdl2objc (http://code.google.com/p/wsdl2objc/)
169
Curso iOS 8
Se trata de una aplicacin de Mac que solicita la URL del archivo WSDL y genera unas clases Objective C que podremos incorporar a nuestro proyecto.
Este proyecto es antiguo y no usa ARC as que o bien desactivamos ARC en esos archivos
con el flag del compilador -fno-objc-arc o bien utilizamos la herramienta de migracin automtica:
Gua de Apple: Migracin a ARC (https://developer.apple.com/library/ios/
releasenotes/ObjectiveC/RN-TransitioningToARC/RN-TransitioningToARC.pdf)
Stack Overflow: Desactivar ARC en un archivo (http://stackoverflow.com/
questions/6646052/how-can-i-disable-arc-for-a-single-file-in-a-project)
Curso iOS 8
READ: Leer
UPDATE: Actualizar
DELETE: Borrar
Y en castellano muchas veces ABM: Alta, Baja y Modificacin, obviando la lectura de datos.
171
172
Captulo 27
Cmara: Fotos
27.1 Introduccin
Para sacar una foto con la cmara del dispositivo utilizamos el controlador UIImagePickerController.
Antes de poder hacerlo hay que comprobar si el dispositivo realmente tiene una cmara
de fotos (o varias).
Por ejemplo estos dispositivos no tienen cmara:
Simulador de iOS
iPad de primera generacin
iPod touch de la primera a la tercera generacin
Ms informacin:
Wikipedia: Lista de dispositivos iOS (http://en.wikipedia.org/wiki/
List_of_iOS_devices)
En los dispositivos sin cmara deberemos ofrecer la alternativa de obtener una foto del lbum de fotos.
Curso iOS 8
isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[self showImagePicker:UIImagePickerControllerSourceTypeCamera];
} else {
[self
showImagePicker:UIImagePickerControllerSourceTypePhotoLibrary];
}
}
174
Curso iOS 8
- (void)logCameraDevices
{
NSLog(@"AVCaptureDevice devices: %@", [AVCaptureDevice devices]);
}
27.5 Referencias:
Gua Apple: Camera Programming Topics for iOS (http://developer.apple.com/
library/ios/documentation/AudioVideo/Conceptual/
CameraAndPhotoLib_TopicsForIOS/CameraAndPhotoLib_TopicsForIOS.pdf)
Referencia: UIImagePickerController (http://developer.apple.com/library/ios/
documentation/uikit/reference/UIImagePickerController_Class/
UIImagePickerController_Class.pdf)
Referencia: UIImagePickerControllerDelegate (http://developer.apple.com/
library/ios/documentation/uikit/reference/
UIImagePickerControllerDelegate_Protocol/
UIImagePickerControllerDelegate_Protocol.pdf)
Referencia: AVCaptureDevice (https://developer.apple.com/library/mac/
documentation/AVFoundation/Reference/AVCaptureDevice_Class/
AVCaptureDevice_Class.pdf)
175
176
Captulo 28
Cmara en el Simulador
El simulador no permite utilizar directamente la cmara.
Para usar una imagen guardada previamente en la app Fotos del Simulador:
1. Mantener pulsado Alt y el botn del ratn
177
Curso iOS 8
178
Curso iOS 8
179
180
Curso iOS 8
Curso iOS 8
Curso iOS 8
28.4 Referencias
Stack Overflow (http://stackoverflow.com/questions/1250199/how-do-i-addphotos-to-the-iphone-simulator-for-osx)
182
Captulo 29
29.1.1 Libro
Ttulo
Autor
ISBN
Portada (foto)
Prestado a (amigo)
Fecha del prstamo
183
Curso iOS 8
29.1.2 Autor
Nombre
Libros
29.1.3 Amigo
Nombre
Libros
Telfono
29.2 Pantallas
Documentacin (https://developers.google.com/books/docs/v1/getting_started)
Ejemplo de llamada a Google Books API:
https://www.googleapis.com/books/v1/volumes?q=isbn:0789723107
Ejemplo de thumbnail:
http://bks5.books.google.es/
books?id=_VYvIG5TYXEC&printsec=frontcover&img=1&zoom=1&source=gbs_api
184
Curso iOS 8
29.6 Recursos
Portadas e ISBNs Libros.zip (/descargas/Libros.zip)
Property list Libros.plist (/descargas/Libros.plist)
En ModeloLibros.m
- (void)usarDocumentoConCompletion:(usarDocumentoCompletion)completion
{
if (![[NSFileManager defaultManager]
fileExistsAtPath:[self.librosDoc.fileURL path]]) {
[self.librosDoc saveToURL:self.librosDoc.fileURL
forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL
success) {
NSLog(@"El documento est creado, hacer consultas...");
completion();
}];
} else if (self.librosDoc.documentState == UIDocumentStateClosed) {
[self.librosDoc openWithCompletionHandler:^(BOOL success) {
NSLog(@"El documento est abierto, hacer consultas...");
completion();
}];
} else if (self.librosDoc.documentState == UIDocumentStateNormal) {
NSLog(@"El documento ya est abierto, hacer consultas...");
completion();
}
}
185
Curso iOS 8
As que si has creado un tableView dentro de un ViewController normal y quieres habilitarlo debes crear este mtodo:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
}
#pragma mark - editButtonItem
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:animated];
}
Referencias:
Gua Apple: ViewController PG for iOS (http://developer.apple.com/library/ios/
featuredarticles/ViewControllerPGforiPhoneOS/ViewControllerPGforiOS.pdf)
Buscar: Enabling Edit Mode in a View Controller
Curso iOS 8
187
Curso iOS 8
Curso iOS 8
Necesitamos conectar los outlets y atender a los target-actions de estos views como hacemos siempre en el mismo ViewController que presenta la semimodal.
En archivo.h
@property (weak, nonatomic) IBOutlet UITextField *fechaInicioText;
@property (weak, nonatomic) IBOutlet UITextField *fechaFinText;
@property (weak, nonatomic) IBOutlet UIView *fechaView;
@property (weak, nonatomic) IBOutlet UIDatePicker *fechaPicker;
En archivo.m
#pragma mark - Setup
- (void)setup
{
ddMMyyyy = [[NSDateFormatter alloc] init];
[ddMMyyyy setDateFormat:@"dd/MM/yyyy"];
fechaInicioText.inputView = fechaView;
fechaFinText.inputView = fechaView;
}
#pragma mark - Fecha
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField == fechaInicioText && fechaInicio) fechaPicker.date =
fechaInicio;
if(textField == fechaFinText && fechaFin) fechaPicker.date =
fechaFin;
fechaSelectedText = textField;
return YES;
}
- (IBAction)fechaCancelarTap:(id)sender {
[self.view endEditing:YES];
}
- (IBAction)fechaAceptarTap:(id)sender {
if(fechaSelectedText == fechaInicioText) fechaInicio =
fechaPicker.date;
if(fechaSelectedText == fechaFinText) fechaFin = fechaPicker.date;
fechaSelectedText.text = [ddMMyyyy stringFromDate:fechaPicker.date];
189
Curso iOS 8
[self.view endEditing:YES];
}
<Foundation/Foundation.h>
"Libro+Metodos.h"
"Autor+Metodos.h"
"Amigo+Metodos.h"
(strong,
(strong,
(strong,
(strong,
nonatomic)
nonatomic)
nonatomic)
nonatomic)
NSURL *documentsUrl;
NSURL *imagesUrl;
NSURL *librosUrl;
UIManagedDocument *librosDoc;
typedef void(^usarDocumentoCompletion)(void);
- (void)usarDocumentoConCompletion:(usarDocumentoCompletion)completion;
@end
En Libros.m
#import "Libros.h"
@implementation Libros
+ (Libros *)sharedInstance
{
static Libros *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[Libros alloc] init];
});
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
// initializations
190
Curso iOS 8
}
return self;
}
- (NSURL *)documentsUrl
{
if(!_documentsUrl) {
_documentsUrl = [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
lastObject];
}
return _documentsUrl;
}
- (NSURL *)imagesUrl
{
if(!_imagesUrl) {
_imagesUrl = [self.documentsUrl
URLByAppendingPathComponent:@"images"];
if(![[NSFileManager defaultManager] fileExistsAtPath:[_imagesUrl
path]]) {
NSError *error;
[[NSFileManager defaultManager]
createDirectoryAtURL:_imagesUrl withIntermediateDirectories:YES
attributes:nil error:&error];
if(error) NSLog(@"imagesUrl: %@", error);
}
}
return _imagesUrl;
}
- (NSURL *)librosUrl
{
if(!_librosUrl) {
_librosUrl = [self.documentsUrl
URLByAppendingPathComponent:@"librosDoc"];
}
return _librosUrl;
}
- (UIManagedDocument *)librosDoc
{
if(!_librosDoc) {
_librosDoc = [[UIManagedDocument alloc]
initWithFileURL:self.librosUrl];
191
Curso iOS 8
}
return _librosDoc;
}
- (void)usarDocumentoConCompletion:(usarDocumentoCompletion)completion
{
if (![[NSFileManager defaultManager]
fileExistsAtPath:[self.librosDoc.fileURL path]]) {
[self.librosDoc saveToURL:self.librosDoc.fileURL
forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL
success) {
NSLog(@"El documento est creado, hacer consultas...");
completion();
}];
} else if (self.librosDoc.documentState == UIDocumentStateClosed) {
[self.librosDoc openWithCompletionHandler:^(BOOL success) {
NSLog(@"El documento est abierto, hacer consultas...");
completion();
}];
} else if (self.librosDoc.documentState == UIDocumentStateNormal) {
NSLog(@"El documento ya est abierto, hacer consultas...");
completion();
}
}
@end
192
Foundation
194
Captulo NS.1
NSLog
huecos ni parmetros");
hueco int: %i", 2);
hueco float: %f", 3.14);
hueco float sin ceros decimales: %g", 6.0);
hueco objeto (usa mensaje description): %@", @"Un
un objeto");
NS.1.1 Referencias
Gua Apple: Foundation Functions (https://developer.apple.com/library/mac/
documentation/cocoa/reference/foundation/miscellaneous/
foundation_functions/Foundation_Functions.pdf)
Gua Apple: Strings (https://developer.apple.com/library/ios/documentation/
Cocoa/Conceptual/Strings/Strings.pdf)
195
196
Captulo NS.2
NSObject
NS.2.1 Introspeccin
Todos los objetos que heredan de NSObject implementan estos tres mtodos:
isKindOfClass: devuelve si un objeto es este tipo de class (herencia incluida)
isMemberOfClass: devuelve si un objeto es exactamente este tipo de class (sin
herencia)
respondsToSelector: devuelve si un objeto responde al un mtodo concreto
Son muy tiles para comprobar si un objeto pertenece a una clase antes de hacer un cast
(conversin de tipos muy peligrosa si nos equivocamos de tipo).
A este tipo de comprobaciones se las denomina Introspeccin, es decir, inspeccionar de forma segura los tipos y valores internos de los objetos.
Para obtener el argumento para comparar con una clase utilizar el mensaje class:
[NSString class]
Curso iOS 8
Es importante para no cometer errores darse cuenta que los dos puntos : forman parte de
los nombres de los mtodos.
198
Captulo NS.3
NSString
Clase fundamental para manejar strings.
La sintaxis ms sencilla para crear uno es:
NSString *unString = @"Hola";
Los objetos NSString son inmutables, es decir, no se pueden cambiar una vez creados.
La clase NSMutableString s permite ser cambiada, pero trabajar con strings inmutables
es ms fcil de lo que parece.
Para obtener un nuevo string a partir de otro basta con crear uno nuevo utilizando un formato o aadiendo texto detrs. Hay multitud de funciones que nos ayudan con esto.
199
Curso iOS 8
NS.3.1.2 stringByAppendingString
NSString *errorTag = @"Error: ";
NSString *errorString = @"premature end of file.";
NSString *errorMessage = [errorTag stringByAppendingString:errorString];
NS.3.2 Tareas
NS.3.2.1 Crear e inicializar
+
+
+
+
+
+
+
string
init
initWithBytes:length:encoding:
initWithBytesNoCopy:length:encoding:freeWhenDone:
initWithCharacters:length:
initWithCharactersNoCopy:length:freeWhenDone:
initWithString:
initWithCString:encoding:
initWithUTF8String:
initWithFormat:
initWithFormat:arguments:
initWithFormat:locale:
initWithFormat:locale:arguments:
initWithData:encoding:
stringWithFormat:
localizedStringWithFormat:
stringWithCharacters:length:
stringWithString:
stringWithCString:encoding:
stringWithUTF8String:
stringWithContentsOfFile:encoding:error:
initWithContentsOfFile:encoding:error:
stringWithContentsOfFile:usedEncoding:error:
initWithContentsOfFile:usedEncoding:error:
200
stringWithContentsOfURL:encoding:error:
initWithContentsOfURL:encoding:error:
stringWithContentsOfURL:usedEncoding:error:
initWithContentsOfURL:usedEncoding:error:
Curso iOS 8
writeToFile:atomically:encoding:error:
writeToURL:atomically:encoding:error:
writeToFile:atomically: Deprecated in iOS 2.0
writeToURL:atomically: Deprecated in iOS 2.0
NS.3.2.5 Tamao
length
lengthOfBytesUsingEncoding:
maximumLengthOfBytesUsingEncoding:
characterAtIndex:
getCharacters:range:
getBytes:maxLength:usedLength:encoding:options:range:remainingRange:
getCharacters: Deprecated in iOS 4.0
componentsSeparatedByString:
componentsSeparatedByCharactersInSet:
stringByTrimmingCharactersInSet:
substringFromIndex:
substringWithRange:
substringToIndex:
rangeOfCharacterFromSet:
rangeOfCharacterFromSet:options:
rangeOfCharacterFromSet:options:range:
rangeOfString:
rangeOfString:options:
rangeOfString:options:range:
rangeOfString:options:range:locale:
201
enumerateLinesUsingBlock:
enumerateSubstringsInRange:options:usingBlock:
NS.3.2.12 Rangos
getLineStart:end:contentsEnd:forRange:
lineRangeForRange:
getParagraphStart:end:contentsEnd:forRange:
paragraphRangeForRange:
rangeOfComposedCharacterSequenceAtIndex:
rangeOfComposedCharacterSequencesForRange:
caseInsensitiveCompare:
localizedCaseInsensitiveCompare:
compare:
localizedCompare:
compare:options:
compare:options:range:
compare:options:range:locale:
localizedStandardCompare:
hasPrefix:
hasSuffix:
isEqualToString:
hash
202
capitalizedString
capitalizedStringWithLocale:
lowercaseString
lowercaseStringWithLocale:
uppercaseString
uppercaseStringWithLocale:
Curso iOS 8
Curso iOS 8
doubleValue
floatValue
intValue
integerValue
longLongValue
boolValue
availableStringEncodings
defaultCStringEncoding
localizedNameOfStringEncoding:
canBeConvertedToEncoding:
dataUsingEncoding:
dataUsingEncoding:allowLossyConversion:
description
fastestEncoding
smallestEncoding
pathWithComponents:
pathComponents
completePathIntoString:caseSensitive:matchesIntoArray:filterTypes:
fileSystemRepresentation
getFileSystemRepresentation:maxLength:
isAbsolutePath
lastPathComponent
pathExtension
stringByAbbreviatingWithTildeInPath
stringByAppendingPathComponent:
stringByAppendingPathExtension:
stringByDeletingLastPathComponent
stringByDeletingPathExtension
stringByExpandingTildeInPath
stringByResolvingSymlinksInPath
stringByStandardizingPath
stringsByAppendingPaths:
203
Curso iOS 8
NS.3.3 Referencias
Gua Apple: Strings (https://developer.apple.com/library/ios/documentation/
Cocoa/Conceptual/Strings/Strings.pdf)
Gua Apple: Data Formatting (https://developer.apple.com/library/ios/
documentation/Cocoa/Conceptual/DataFormatting/DataFormatting.pdf)
204
Captulo NS.4
NSMutableString
Versin mutable de NSString. Se usa menos de lo que parece.
Hereda de NSString por lo que se pueden usar los mismos mtodos.
Pero puede usarse para cambiar un string in situ:
NSMutableString *ms = [[NSMutableString alloc] initWithString:@"0."];
NSMutableString *ms = [NSMutableString stringWithString:@"0."];
[ms appendString:digit];
NS.4.1 Tareas
NS.4.1.1 Creacin e inicializacin
+ stringWithCapacity:
initWithCapacity:
Ejemplo:
self.display = [NSMutableString stringWithCapacity:20];
NS.4.1.2 Modificacin
appendFormat:
appendString:
deleteCharactersInRange:
insertString:atIndex:
replaceCharactersInRange:withString:
replaceOccurrencesOfString:withString:options:range:
setString:
205
Curso iOS 8
Ejemplo:
[self.display appendString:digito];
NS.4.2 Referencias
Gua Apple: Strings (https://developer.apple.com/library/ios/documentation/
Cocoa/Conceptual/Strings/Strings.pdf)
206
Captulo NS.5
NSNumber
NSNumber es una subclase de NSValue que ofrece como valor cualquier tipo numrico de
C.
Define un conjunto de mtodos para establecer y obtener el valor con o sin signo de: char,
short int, int, long int, long long int, float, double o BOOL.
Tambin define un mtodo compare: para determinar el orden de dos objetos NSNumber.
Para crear un NSNumber a partir de una constante o una operacin entre constantes se puede usar:
NSNumber *x = @2;
NSNumber *y = @(2 + 2); // El contenido es 4
NS.5.1 Tareas
NS.5.1.1 Creacin
+
+
+
+
+
+
+
+
+
+
+
numberWithBool:
numberWithChar:
numberWithDouble:
numberWithFloat:
numberWithInt:
numberWithInteger:
numberWithLong:
numberWithLongLong:
numberWithShort:
numberWithUnsignedChar:
numberWithUnsignedInt:
207
+
+
+
+
numberWithUnsignedInteger:
numberWithUnsignedLong:
numberWithUnsignedLongLong:
numberWithUnsignedShort:
NS.5.1.2 Inicializacin
initWithBool:
initWithChar:
initWithDouble:
initWithFloat:
initWithInt:
initWithInteger:
initWithLong:
initWithLongLong:
initWithShort:
initWithUnsignedChar:
initWithUnsignedInt:
initWithUnsignedInteger:
initWithUnsignedLong:
initWithUnsignedLongLong:
initWithUnsignedShort:
boolValue
charValue
decimalValue
doubleValue
floatValue
intValue
integerValue
longLongValue
longValue
shortValue
unsignedCharValue
unsignedIntegerValue
unsignedIntValue
unsignedLongLongValue
unsignedLongValue
unsignedShortValue
Curso iOS 8
Curso iOS 8
NS.5.1.5 Comparacin
compare:
isEqualToNumber:
209
210
Captulo NS.6
NSDate
NS.6.2 Formatos
ddmmyyyy.locale = esLocale;
NSLog(@"formato ddmmyyyy: %@", [ddmmyyyy stringFromDate:fecha]);
NS.6.3 Tareas
NS.6.3.1 Creacin e inicializacin
+
+
+
+
+
date
dateWithTimeIntervalSinceNow:
dateWithTimeInterval:sinceDate:
dateWithTimeIntervalSinceReferenceDate:
dateWithTimeIntervalSince1970:
init
initWithTimeIntervalSinceNow:
initWithTimeInterval:sinceDate:
initWithTimeIntervalSinceReferenceDate:
initWithTimeIntervalSince1970:
NS.6.3.3 Comparacin
isEqualToDate:
earlierDate:
laterDate:
compare:
timeIntervalSinceDate:
timeIntervalSinceNow
timeIntervalSinceReferenceDate
timeIntervalSinceReferenceDate
timeIntervalSince1970
212
Curso iOS 8
Curso iOS 8
NS.6.4 Referencias
213
214
Captulo NS.7
NSValue
Es un objeto genrico para empaquetar otros datos que no son objetos (p.ej. structs de C).
Ejemplo:
NSValue *edgeInsetsObject = [NSValue
valueWithUIEdgeInsets:UIEdgeInsetsMake(1,1,1,1)];
NS.7.1 Tareas
NS.7.1.1 Creacin e inicializacin
+
+
+
+
+
initWithBytes:objCType:
valueWithBytes:objCType:
value:withObjCType:
valueWithNonretainedObject:
valueWithPointer:
valueWithRange:
getValue:
nonretainedObjectValue
objCType
pointerValue
rangeValue
NS.7.1.3 Comparacin
isEqualToValue:
215
216
Captulo NS.8
NSData
NS.8.1 Tareas
NS.8.1.1 Creacin e inicializacin
+
+
+
+
+
+
+
+
+
data
dataWithBytes:length:
dataWithBytesNoCopy:length:
dataWithBytesNoCopy:length:freeWhenDone:
dataWithContentsOfFile:
dataWithContentsOfFile:options:error:
dataWithContentsOfURL:
dataWithContentsOfURL:options:error:
dataWithData:
initWithBase64EncodedData:options:
initWithBase64EncodedString:options:
initWithBytes:length:
initWithBytesNoCopy:length:
initWithBytesNoCopy:length:deallocator:
initWithBytesNoCopy:length:freeWhenDone:
initWithContentsOfFile:
initWithContentsOfFile:options:error:
initWithContentsOfURL:
initWithContentsOfURL:options:error:
initWithData:
217
bytes
description
enumerateByteRangesUsingBlock:
getBytes:length:
getBytes:range:
subdataWithRange:
rangeOfData:options:range:
NS.8.1.5 Persistencia
218
writeToFile:atomically:
writeToFile:options:error:
writeToURL:atomically:
writeToURL:options:error:
Curso iOS 8
Captulo NS.9
NSArray
Coleccin ordenada de objetos.
Inmutable. Una vez creado no se pueden aadir o quitar objetos.
Normalmente se crea manipulando otros arrays o mediante @[].
219
220
Captulo NS.10
NSMutableArray
Versin mutable de NSArray.
Se crea con alloc/init o
+ (id)arrayWithCapacity:(NSUInteger)numItems; // puede crecer ms que
numItems (espacio inicial)
+ (id)array; // [NSMutableArray array] es igual que [[NSMutableArray
alloc] init]
221
222
Captulo NS.11
NSDictionary
NS.11.0.1 NSDictionary
Coleccin inmutable de objetos que se introducen y extraen mediante su clave.
Todas las claves y valores son mantenidas de manera strong por un NSDictionary.
Se pueden crear con esta sintaxis:
@{ key1 : value1, key2 : value2, key3 : value3 }
NSDictionary *colors = @{ @green : [UIColor greenColor],
@blue : [UIColor blueColor],
@red : [UIColor redColor] };
NS.11.1 Tareas
NS.11.1.1 Creacin
+
+
+
+
dictionary
dictionaryWithContentsOfFile:
dictionaryWithContentsOfURL:
dictionaryWithDictionary:
223
+
+
+
+
Curso iOS 8
dictionaryWithObject:forKey:
dictionaryWithObjects:forKeys:
dictionaryWithObjects:forKeys:count:
dictionaryWithObjectsAndKeys:
NS.11.1.2 Inicializacin
initWithContentsOfFile:
initWithContentsOfURL:
initWithDictionary:
initWithDictionary:copyItems:
initWithObjects:forKeys:
initWithObjects:forKeys:count:
initWithObjectsAndKeys:
init
NS.11.1.5 Comparacin
isEqualToDictionary:
allKeys
allKeysForObject:
allValues
getObjects:andKeys:
objectForKey:
objectForKeyedSubscript:
objectsForKeys:notFoundMarker:
valueForKey:
NS.11.1.7 Enumeracin
224
keyEnumerator
objectEnumerator
enumerateKeysAndObjectsUsingBlock:
enumerateKeysAndObjectsWithOptions:usingBlock:
Curso iOS 8
NS.11.1.8 Ordenacin
keysSortedByValueUsingSelector:
keysSortedByValueUsingComparator:
keysSortedByValueWithOptions:usingComparator:
NS.11.1.9 Filtrado
keysOfEntriesPassingTest:
keysOfEntriesWithOptions:passingTest:
NS.11.1.10 Persistencia
writeToFile:atomically:
writeToURL:atomically:
fileCreationDate
fileExtensionHidden
fileGroupOwnerAccountID
fileGroupOwnerAccountName
fileHFSCreatorCode
fileHFSTypeCode
fileIsAppendOnly
fileIsImmutable
fileModificationDate
fileOwnerAccountID
fileOwnerAccountName
filePosixPermissions
fileSize
fileSystemFileNumber
fileSystemNumber
fileType
NS.11.1.12 Descripcin
description
descriptionInStringsFileFormat
descriptionWithLocale:
descriptionWithLocale:indent:
225
226
Captulo NS.12
NSMutableDictionary
Versin mutable de NSDictionary
Se crean mediante alloc/init o uno de los mtodos de clase
+ (id)dictionary... class methods.
(void)setObject:(id)anObject forKey:(id)key;
(void)removeObjectForKey:(id)key;
(void)removeAllObjects;
(void)addEntriesFromDictionary:(NSDictionary *)otherDictionary;
NS.12.1 Tareas
NS.12.1.1 Creacin e inicializacin
+
dictionaryWithCapacity:
initWithCapacity:
init
dictionaryWithSharedKeySet:
setObject:forKey:
setObject:forKeyedSubscript:
setValue:forKey:
addEntriesFromDictionary:
setDictionary:
227
228
Curso iOS 8
Captulo NS.13
NSSet
NS.13.1 Tareas
NS.13.1.1 Creacin
+
+
+
+
+
+
set
setWithArray:
setWithObject:
setWithObjects:
setWithObjects:count:
setWithSet:
setByAddingObject:
setByAddingObjectsFromSet:
setByAddingObjectsFromArray:
NS.13.1.2 Inicializacin
initWithArray:
initWithObjects:
initWithObjects:count:
initWithSet:
initWithSet:copyItems:
init
229
allObjects
anyObject
containsObject:
filteredSetUsingPredicate:
makeObjectsPerformSelector:
makeObjectsPerformSelector:withObject:
member:
objectEnumerator
enumerateObjectsUsingBlock:
enumerateObjectsWithOptions:usingBlock:
objectsPassingTest:
objectsWithOptions:passingTest:
NS.13.1.5 Comparacin
isSubsetOfSet:
intersectsSet:
isEqualToSet:
valueForKey:
setValue:forKey:
NS.13.1.8 description
description
descriptionWithLocale:
230
Curso iOS 8
Captulo NS.14
NSMutableSet
Coleccin desordenada y mutable de objetos. Versin mutable de NSSet.
Se utilizan cuando la velocidad de comprobacin de si un objeto existe o no dentro del set
es importante. Para esta tarea son ms rpidos que los arrays.
NS.14.1 Tareas
NS.14.1.1 Creacin
+ setWithCapacity:
initWithCapacity:
init
addObject:
filterUsingPredicate:
removeObject:
removeAllObjects
addObjectsFromArray:
NS.14.1.3 Combinacin
unionSet:
minusSet:
intersectSet:
setSet:
231
232
Captulo NS.15
NSOrderedSet
Coleccin ordenada inmutable de objetos.
Se utilizan cuando la velocidad de comprobacin de si un objeto existe o no dentro del set
es importante. Para esta tarea son ms rpidos que los arrays.
NS.15.1 Tareas
NS.15.1.1 Creacin
+
+
+
+
+
+
+
+
+
+
orderedSet
orderedSetWithArray:
orderedSetWithArray:range:copyItems:
orderedSetWithObject:
orderedSetWithObjects:
orderedSetWithObjects:count:
orderedSetWithOrderedSet:
orderedSetWithOrderedSet:range:copyItems:
orderedSetWithSet:
orderedSetWithSet:copyItems:
NS.15.1.2 Inicializacin
initWithArray:
initWithArray:copyItems:
initWithArray:range:copyItems:
initWithObject:
initWithObjects:
initWithObjects:count:
initWithOrderedSet:
233
initWithOrderedSet:copyItems:
initWithOrderedSet:range:copyItems:
initWithSet:
initWithSet:copyItems:
init
containsObject:
enumerateObjectsAtIndexes:options:usingBlock:
enumerateObjectsUsingBlock:
enumerateObjectsWithOptions:usingBlock:
firstObject
lastObject
objectAtIndex:
objectAtIndexedSubscript:
objectsAtIndexes:
indexOfObject:
indexOfObject:inSortedRange:options:usingComparator:
indexOfObjectAtIndexes:options:passingTest:
indexOfObjectPassingTest:
indexOfObjectWithOptions:passingTest:
indexesOfObjectsAtIndexes:options:passingTest:
indexesOfObjectsPassingTest:
indexesOfObjectsWithOptions:passingTest:
objectEnumerator
reverseObjectEnumerator
reversedOrderedSet
getObjects:range:
234
Curso iOS 8
Curso iOS 8
NS.15.1.7 Comparacin
isEqualToOrderedSet:
intersectsOrderedSet:
intersectsSet:
isSubsetOfOrderedSet:
isSubsetOfSet:
NS.15.1.9 Filtrado
filteredOrderedSetUsingPredicate:
NS.15.1.10 Descripcin
description
descriptionWithLocale:
descriptionWithLocale:indent:
NS.15.1.11 Conversin
array
set
235
236
Captulo NS.16
NSMutableOrderedSet
Versin mutable de NSOrderedSet.
NS.16.1 Tareas
NS.16.1.1 Creacin
+ orderedSetWithCapacity:
initWithCapacity:
init
addObject:
addObjects:count:
addObjectsFromArray:
insertObject:atIndex:
setObject:atIndexedSubscript:
insertObjects:atIndexes:
removeObject:
removeObjectAtIndex:
removeObjectsAtIndexes:
removeObjectsInArray:
removeObjectsInRange:
removeAllObjects
replaceObjectAtIndex:withObject:
replaceObjectsAtIndexes:withObjects:
replaceObjectsInRange:withObjects:count:
setObject:atIndex:
moveObjectsAtIndexes:toIndex:
237
exchangeObjectAtIndex:withObjectAtIndex:
filterUsingPredicate:
NS.16.1.3 Ordenacin
sortUsingDescriptors:
sortUsingComparator:
sortWithOptions:usingComparator:
sortRange:options:usingComparator:
NS.16.1.4 Combinacin
238
intersectOrderedSet:
intersectSet:
minusOrderedSet:
minusSet:
unionOrderedSet:
unionSet:
Curso iOS 8
Captulo NS.17
NSCountedSet
Coleccin mutable, desordenada de objetos indistintos.
Util en el caso de necesitar llevar la cuenta del nmero de veces que se ha aadido un mismo elemento.
NS.17.1 Tareas
NS.17.1.1 Inicializacin
initWithArray: initWithSet: initWithCapacity:
NS.17.1.4 Enumeracin
objectEnumerator
239
240
Captulo NS.18
Enumeracin rpida
NS.18.1 Sentencia for(... in ...) { ... }
Utilizado para pasar cmodamente por todos los miembros de una coleccin de manera
rpida y eficiente
241
NSDictionary *diccionario = @{
@"Nombre" : @"Juan",
@"Apellido" : @"Fernndez",
@"Edad" : @22
};
242
Curso iOS 8
Captulo NS.19
Sintaxis Simple
NS.19.1 Crear nuevo proyecto de Xcode Single View
El archivo ViewController.m inicialmente debera tener un cdigo similar a este:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Aqu insertaremos nuestro cdigo y
// veremos los resultados en la consola de depuracin
}
@end
NS.19.2 NSString
NSString *textoSimple = @"Esto es un texto";
NSLog(@"textoSimple: %@", textoSimple);
NS.19.3 NSNumber
NSNumber *numero = [NSNumber numberWithInt:20];
NSLog(@"numero: %@", numero);
NSNumber *numeroSimple = @20;
NSLog(@"numeroSimple: %@", numeroSimple);
NSNumber *numeroSumado = [NSNumber numberWithInt:20+2];
NSLog(@"numeroSumado: %@", numeroSumado);
243
NS.19.4 NSArray
NSArray *array = @[
@"Lunes",
@"Martes",
@"Mircoles",
@"Jueves",
@"Viernes"
];
NSLog(@"array (%i): %@", [array count], array);
NSLog(@"enumeracin rpida array: ");
for (NSString *elemento in array) {
NSLog(@"elemento: %@", elemento);
}
NS.19.5 NSDictionary
NSDictionary *diccionario = @{
@"Nombre" : @"Fer",
@"Apellido" : @"Alava",
@"Edad" : @39
};
NSLog(@"diccionario (%i): %@", [diccionario count], diccionario);
NSLog(@"enumeracin rpida diccionario: ");
for (id clave in diccionario) {
//id valor = [diccionario objectForKey:clave];
id valor = [diccionario valueForKey:clave];
NSLog(@"elemento %@ => %@", clave, valor);
}
NS.19.6 NSSet
NSSet *conjunto = [NSSet setWithArray:@[
@"rojo",
@"verde",
@"azul"
]];
NSLog(@"conjunto (%i): %@", [conjunto count], conjunto);
244
Curso iOS 8
Curso iOS 8
NS.19.7 NSCountedSet
NSCountedSet *conjuntoConContador = [NSCountedSet setWithArray:@[
@"rojo",
@"rojo",
@"verde",
@"verde",
@"verde",
@"azul"
]];
NSLog(@"conjunto (%i): %@", [conjuntoConContador count],
conjuntoConContador);
NSLog(@"enumeracin rpida conjuntoConContador: ");
for (NSString *elemento in conjuntoConContador) {
NSLog(@"elemento (%i): %@", [conjuntoConContador
countForObject:elemento], conjuntoConContador);
}
245
246
Captulo NS.20
Property Lists
El trmino Property List se utiliza para denotar una coleccin que contiene solo objetos y
colecciones bsicos. Es solo una frase.
Sera el equivalente a un JSON de JavaScript.
Estos tipos y colecciones bsicos son exactamente:
NSArray, NSDictionary, NSNumber, NSString, NSDate, NSData o sus versiones
mutables.
Por ejemplo:
Un NSArray de NSString es una Property List
List.
Un NSArray ser una Property List si todos los objetos que hay dentro pertenece a
esos tipos bsicos.
Un NSDictionary es una Property List si y solo si todas las claves y valores tambin pertenece a esos tipos bsicos.
Ejemplos:
Un NSArray de NSDictionarys cuyas claves sean NSStrings y valores sean
NSNumbers es una Property List
List.
Y por qu se define este trmino?
Porque el SDK tiene muchos mtodos que requieren para operar Property Lists
Lists.
247
Curso iOS 8
Por ejemplo:
- (void)writeToFile:(NSString *)path atomically:(BOOL)atom;
Este mtodo solo se le puede mandar a un NSArray o NSDictionary que sean Property
Lists
Lists.
248
Captulo NS.21
NSUserDefaults
Espacio de almacenamiento ligero para Property Lists
Es bsicamente un diccionario que persiste entre ejecuciones de nuestra aplicacin.
No es una base de datos completa, solo se guardan cosas pequeas ah.
Se escriben y leen mediante una instacia compartida que se obtiene mediante: [NSUserDefaults standardUserDefaults].
[[NSUserDefaults standardUserDefaults] setArray:rvArray
forKey:@"RecentlyViewed"];
Mtodos:
- (void)setDouble:(double)aDouble forKey:(NSString *)key;
- (NSInteger)integerForKey:(NSString *)key;
- (void)setObject:(id)obj forKey:(NSString *)key; // obj debe ser
Property List
- (NSArray *)arrayForKey:(NSString *)key; // devuevle nil si el valor
para esa clave no es un NSArray
249
250
Captulo NS.22
Singleton
NS.22.1 Interfaz pblico
En MiSingleton.h:
#import <Foundation/Foundation.h>
@interface MiSingleton : NSObject
+ (MiSingleton *)sharedInstance;
@end
NS.22.2 Implementacin
En MiSingleton.m:
@implementation MiSingleton
+ (MiSingleton *)sharedInstance
{
static MiSingleton *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MiSingleton alloc] init];
});
return sharedInstance;
}
@end
251
252
Curso iOS 8
UIKit
254
Captulo UI.1
UIViewController
UI.1.1 Ciclo de vida
Lo nico, la geometra de las views no est establecida an. En este momento no sabemos
si estamos en un iPhone 5 o en un iPad. As que no hay que realizar inicializacin que dependa de la geometra.
Justo antes de aparecer en la pantalla se nos notifica con:
255
Curso iOS 8
- (void)viewWillAppear:(BOOL)animated;
El View Controller se carga una vez, pero puede aparecer y desaparecer de la pantalla muchas veces.
Si pones cdigo de inicializacin aqu se ejecutar muchas veces tambin. Aqu si est establecida la geometra.
Tambin somos avisados cuando el View Controller desaparecer de la pantalla.
Estes lugar es til para cdigo de limpieza (desuscripcin de notificaciones)
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self rememberScrollPosition];
[self saveDataToPermanentStore];
}
Se llaman cada vez que el frame cambia y sus subviews son reubicadas, por ejemplo con la
autorotacin.
Aqu se pueden resetear los frames de nuestras views o establecer otras propiedades que
son afectadas por la geometra. Entre will y did, ocurre el Autolayout.
UI.1.1.2 Autorotacin
Cuando se rota el dispositivo el view ms alto de la jerarqua tendr sus bounds reoriendados si:
El ViewController devuelve YES en shouldAutorotate.
El ViewController devuelve la nueva orientacin en
supportedInterfaceOrientations.
La aplicacin permite la rotacin a esa orientacin. Se define en Info.plist.
256
Curso iOS 8
UI.1.1.3 didReceiveMemoryWarning
En situaciones de poca memoria se enva didReceiveMemoryWarning
Todo lo que pueda ser recreado debera aqu ser eliminado (estableciendo sus punteros a
nil).
UI.1.1.4 awakeFromNib
Este mtodo se enva a todos los objetos que salen del Storyboard (incluyendo al controlador).
Ocurre antes de que los outlets se establezcan. Pon el cdigo en otro lugar si es posible
(viewDidLoad o viewWillAppear:).
Todo lo que vaya en el mtodo init tambin deber ir en awakeFromNib porque los mtodos init no se llaman para los objetos que salen del Storyboard.
Ejemplo:
- (void)setup {};
- (void)awakeFromNib { [self setup]; }
// El init designado de UIViewController es initWithNibName:bundle:
- (instancetype)initWithNibName:(NSString *)name bundle:(NSBundle
*)bundle
{
257
Curso iOS 8
UI.1.1.5 Sumario
Instanciacin del from storyboard:
awakeFromNib
outlets establecidos
viewDidLoad
se determina la geometra
viewWillLayoutSubviews: y viewDidLayoutSubviews:
Tantas veces como el MVC aparezca y desaparezca de la pantalla:
viewWillAppear: y viewDidAppear:
si cambia la geometra: viewWillLayoutSubviews: y viewDidLayoutSubviews:
si hay autorotacin will/didRotateTo/From
viewWillDisappear: y viewDidDisappear:
si queda poca memoria: didReceiveMemoryWarning
258
Captulo UI.2
UIView
Una vista o view (p.ej. una subclase de UIView) representa una rea rectangular.
Define un espacio de coordenadas
Su responsabilidad es dibuja y gestionar eventos en ese rectngulo.
Son jerrquicas:
Un view tiene solo una superview:
- (UIView *)superview
El orden de las subviews importa (en dicho array): Las que estn al final del array estn encima de las que estn al principio (porque se dibujan encima).
Una view puede recortar opcionalmente a sus subviews segn sus lmites / bounds. Esto
se cambia en Xcode o bien con un mtodo de UIView
UI.2.1.1 UIWindow
Es el UIView que est en el origen de la jerarqua.
259
Curso iOS 8
Solo hay un UIWindow (generalmente) en una app de iOS. Se trabaja con views no con windows.
Las jerarquas normalmente las hacemos en el Storyboard. Incluso las custom views las
aadimos as y luego les asignamos su clase.
Pero tambin se puede hacer en cdigo:
- (void)addSubview:(UIView *)aView; // sent to aViews (soon to be)
superview
- (void)removeFromSuperview; // sent to the view that is being removed
260
Curso iOS 8
261
Curso iOS 8
Pero puede que queramos dibujar directamente una UIImage con en el drawRect:.
Crear un objeto UIImage desde un archivo del directorio de Xcode:
UIImage *image = [UIImage imageNamed:@"foo.jpg"]; // you did this in
Matchismo
262
Curso iOS 8
Por defecto es UIViewContentModeScaleToFill (estirar o encojer para rellenar los lmites / bounds)
263
264
Captulo UI.3
UIGestureRecognizer
UI.3.1 Cmo reconocemos toques?
Podramos ser avisados con los eventos de toque/touch directamente, pero es ms sencillo ser avisados cuando se reconoce un gesto/gesture
UI.3.2 UIGestureRecognizer
Es la clase que reconoce los gestos. Es abstracta, solo usamos subclases concretas de ella
Hay dos partes para usar un gesture recognizer
1. Aadir un *gesture recognizer* a un `UIView` para pedirle que
reconozca gestos sobre ese view
2. Proporcionar la implementacin de un mtodo para ser llamado cuando
el gesto ocurra
265
Curso iOS 8
Curso iOS 8
El gesture recognizer se mantienen en el estado Possible hasta que inicia el reconocimiento del gesto.
Entonces para a Recognized para gestos discretos como tap.
O pasan a Began para gestos continuos como pan.
En cualquier momento el estado puede pasar a Failed (hay que comprobarlo)
Si el gesto es contnuo, ir pasando al estado Changed hasta llegar a Ended o bien a Cancelled (si al final el gesto no lo era realmente)
As podra implementarse un pan::
- (void)pan:(UIPanGestureRecognizer *)recognizer
{
if ((recognizer.state == UIGestureRecognizerStateChanged) ||
(recognizer.state == UIGestureRecognizerStateEnded)) {
CGPoint translation = [recognizer translationInView:self];
// move something in myself (Im a UIView) by translation.x
and translation.y
// for example, if I were a graph and my origin was set by
an @property called origin
self.origin = CGPointMake(self.origin.x+translation.x,
self.origin.y+translation.y);
[recognizer setTranslation:CGPointZero inView:self];
}
}
UI.3.4.2 UIRotationGestureRecognizer
@property CGFloat rotation; // no es readonly, en radianes
@property (readonly) CGFloat velocity; // readonly; radianes por segundo
UI.3.4.3 UISwipeGestureRecognizer
Se configura para reconocer ciertos tipos de swipe, y entonces se comprueba si el estado es
Recognized
267
Curso iOS 8
UI.3.4.4 UITapGestureRecognizer
Configurar las propiedades y luego comprobar el estado Recognized
@property NSUInteger numberOfTapsRequired; // un tap o doble, triple,
etc.
@property NSUInteger numberOfTouchesRequired; // un dedo, dos, tres...
268
Captulo UI.4
UIScrollView
UI.4.1 App de Ejemplo
269
Curso iOS 8
UI.4.1.1 ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (strong, nonatomic) UIImageView *imageView;
@end
UI.4.1.2 ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
#pragma mark View Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self meterImagenEnScrollView];
[self activarEscaladoEnScrollView];
}
- (void)viewDidAppear:(BOOL)animated
{
[self.scrollView flashScrollIndicators];
}
- (void)meterImagenEnScrollView
{
UIImage *image = [UIImage imageNamed:@"Mireia.jpg"];
self.imageView = [[UIImageView alloc] initWithImage:image];
[self.scrollView addSubview:self.imageView];
[self.scrollView setContentSize:self.imageView.bounds.size];
}
- (void)activarEscaladoEnScrollView
{
self.scrollView.minimumZoomScale = 0.2;
self.scrollView.maximumZoomScale = 2.0;
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
#pragma mark Botones
- (IBAction)min:(UIBarButtonItem *)sender {
[self.scrollView zoomToRect:self.imageView.bounds animated:YES];
}
- (IBAction)cara:(UIBarButtonItem *)sender {
270
Curso iOS 8
271
272
Captulo UI.5
UICollectionViewController
UI.5.1 Mtodos en UICollectionViewDatasource
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView
*)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)view
numberOfItemsInSection:(NSInteger)section {
return [self.fotos count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [cv
dequeueReusableCellWithReuseIdentifier:@"Foto" forIndexPath:indexPath];
return cell;
}
En el Storyboard debemos configurar nuestra celda y adems para poder usar un UICollectionViewController debemos crear una subclase de UICollectionViewCell, ya
que no hay ningn tipo bsico por defecto.
UI.5.3 Referencia
Lecture Stanford 2013 (/descargas/CollectionView.pdf)
273
274
Curso iOS 8
Captulo UI.6
UISplitView
UI.6.1 MaestroTableViewController.h
[objc]
#import <UIKit/UIKit.h>
@interface MaestroTableViewController : UITableViewController
@end
UI.6.2 MaestroTableViewController.m
#import "MaestroTableViewController.h"
#import "DetalleViewController.h"
#import "DetalleViewControllerDelegate.h"
@interface MaestroTableViewController ()
<UISplitViewControllerDelegate,UINavigationControllerDelegate>
@property (strong, nonatomic) UIBarButtonItem *botonSplitView;
@property (strong, nonatomic) UIPopoverController *popover;
@end
@implementation MaestroTableViewController
-(void)awakeFromNib
{
NSLog(@"MaestroTableViewController awakeFromNib");
// Establecerse como delegado del SplitView
self.splitViewController.delegate = self;
// Establecerse como delegado del Detalle Navigation Controller
UINavigationController *detalleNav =
self.splitViewController.viewControllers[1];
detalleNav.delegate = self;
}
275
Curso iOS 8
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"MaestroTableViewController viewDidLoad");
// Uncomment the following line to preserve selection between
presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the
navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return 0;
}
#pragma mark UISplitViewControllerDelegate
-(BOOL)splitViewController:(UISplitViewController *)svc
shouldHideViewController:(UIViewController *)vc
inOrientation:(UIInterfaceOrientation)orientation
{
// No ocultar el master en ninguna orientacin
// return NO;
return UIInterfaceOrientationIsPortrait(orientation);
}
-(void)splitViewController:(UISplitViewController *)splitView
willHideViewController:(UIViewController *)master
withBarButtonItem:(UIBarButtonItem *)barButtonItem
forPopoverController:(UIPopoverController *)popover
{
NSLog(@"Ttulo maestro: %@", self.title);
NSLog(@"Ttulo navigationItem: %@", self.navigationItem.title);
barButtonItem.title = self.navigationItem.title;
self.botonSplitView = barButtonItem;
self.popover = popover;
// Obtener referencia al detalle del splitView
// que es un navigation controller
UINavigationController *detalleNav =
276
Curso iOS 8
self.splitViewController.viewControllers[1];
// Obtener referencia a la pantalla visible del navigation controller
// que debe implementar el protocolo DetalleViewControllerDelegate
id <DetalleViewControllerDelegate> detalle =
(id <DetalleViewControllerDelegate>)detalleNav.topViewController;
NSLog(@"Detalle: %@", detalle);
[detalle ponerBotonSplitView:self.botonSplitView];
}
-(void)splitViewController:(UISplitViewController *)splitView
willShowViewController:(UIViewController *)master
invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
self.botonSplitView = nil;
self.popover = nil;
// Obtener referencia al detalle del splitView
// que es un navigation controller
UINavigationController *detalleNav =
self.splitViewController.viewControllers[1];
// Obtener referencia a la pantalla visible del navigation controller
// que debe implementar el protocolo DetalleViewControllerDelegate
id <DetalleViewControllerDelegate> detalle =
(id <DetalleViewControllerDelegate>)detalleNav.topViewController;
NSLog(@"Detalle: %@", detalle);
[detalle quitarBotonSplitView:barButtonItem];
}
#pragma mark UINavigationControllerDelegate
-(void)navigationController:(UINavigationController
*)navigationController willShowViewController:(UIViewController
*)viewController animated:(BOOL)animated
{
id <DetalleViewControllerDelegate> detalle =
(id <DetalleViewControllerDelegate>)viewController;
if (self.botonSplitView) {
[detalle ponerBotonSplitView:self.botonSplitView];
} else {
[detalle quitarBotonSplitView:self.botonSplitView];
}
}
@end
277
278
Captulo UI.7
UIPopoverController
UI.7.1 Bugs!
UI.7.1.1 Popover segue y viewDidLoad del contenido
El popover segue y la inicializacin del contenido se ejecutan en paralelo y a veces el viewDidLoad se ejecuta antes de terminar la ejecucin del prepareForSegue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(@"prepareForSegue %@", segue.identifier);
if([segue.identifier isEqualToString:@"ToolBarTransicionPopover"]) {
if([segue.destinationViewController
isKindOfClass:[PopoverViewController class]]) {
PopoverViewController *contenido =
segue.destinationViewController;
[contenido setUrl:@"http://www.apple.es/"];
// Debemos llamar a la inicializacin del contenido ya que
// su viewDidLoad podra haberse ejecutado antes de tiempo
[contenido setup];
}
}
}
279
Curso iOS 8
Finalmente, si el Popover ya est abierto debemos cerrarlo, anular nuestra referencia y devolver NO para impedir el segue en shouldPerformSegueWithIdentifier::
-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier
sender:(id)sender
{
// Si abrimos un popover desde un toolbar button no se cerrar
// automticamente. Hay que hacerlo manualmente.
if([identifier isEqualToString:@"ToolBarTransicionPopover"]) {
if([self.toolbarPopoverController isPopoverVisible]) {
[self.toolbarPopoverController dismissPopoverAnimated:YES];
self.toolbarPopoverController = nil;
return NO;
280
Curso iOS 8
}
}
return YES;
}
281
Cocoapods
284
Captulo POD.1
Cocoapods
POD.1.1 Documentacin
http://cocoapods.org
https://github.com/CocoaPods/CocoaPods
POD.1.2 Instalacin
Primero instalar las Command Line Tools de Xcode para disponer de un compilador de C
en el sistema.
sudo gem update --system
sudo gem install cocoapods
pod setup
pod install
pod update
POD.1.4 Referencias
http://nsscreencast.com/episodes/5-cocoapods
http://afnetworking.com
https://github.com/AFNetworking/Xcode-Project-Templates
Heroku Mobile (http://mobile.heroku.com/)
286
Curso iOS 8
Captulo POD.2
ZBarSDK
POD.2.1 Documentacin
http://zbar.sourceforge.net/iphone/sdkdoc/index.html
http://cocoapods.org/?q=zbarsdk
POD.2.2 Instalacin
287
Curso iOS 8
Son necesarios un UIImageView y UITextView en el Storyboard y un UIButton para lanzar la accin de escanear.
ViewController.h
#import <UIKit/UIKit.h>
#import "ZBarSDK.h"
@interface ViewController : UIViewController <ZBarReaderDelegate>
@end
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *resultImage;
@property (weak, nonatomic) IBOutlet UITextView *resultText;
@end
@implementation ViewController
- (IBAction)pressScan:(UIButton *)sender {
// ADD: present a barcode reader that scans from the camera feed
ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
reader.supportedOrientationsMask = ZBarOrientationMaskAll;
ZBarImageScanner *scanner = reader.scanner;
// TODO: (optional) additional reader configuration here
// EXAMPLE: disable rarely used I2/5 to improve performance
[scanner setSymbology: ZBAR_I25
config: ZBAR_CFG_ENABLE
to: 0];
// present and release the controller
[self presentModalViewController:reader animated:YES];
}
- (void)imagePickerController:(UIImagePickerController*)reader
didFinishPickingMediaWithInfo:(NSDictionary*) info
288
Curso iOS 8
{
// ADD: get the decode results
id<NSFastEnumeration> results = [info objectForKey:
ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results)
// EXAMPLE: just grab the first barcode
break;
// EXAMPLE: do something useful with the barcode data
self.resultText.text = symbol.data;
// EXAMPLE: do something useful with the barcode image
self.resultImage.image = [info objectForKey:
UIImagePickerControllerOriginalImage];
// ADD: dismiss the controller (NB dismiss from the *reader*!)
[reader dismissModalViewControllerAnimated:YES];
}
289
Stanford CS193P
292
Captulo S
Stanford CS193p
S.1 Introduccin
Curso de Stanford sobre iOS impartido por Paul Hegarty que se da una o dos veces al ao.
Est disponible libremente en iTunes (gratis y con licencia CC).
Sin duda la mejor referencia disponible para aprender y mantenerse actualizado, por la
calidad de los materiales y videos.
S.2 Presentaciones
S.3 Videos
294
Curso iOS 8
Curso iOS 8
S.4 Referencias
Web Stanford (http://online.stanford.edu/course/developing-ios7-apps-fall-2013)
Curso iTunes (https://itunes.apple.com/us/course/developing-ios-7-apps-for/
id733644550)
295
296
Captulo S.1
Stanford: Lecture 1
S.1.1 Componentes de la Plataforma
Curso iOS 8
S.1.3 MVC
298
Curso iOS 8
S.1.4 Objective C
S.1.5 Referencias
PDF: Lecture 1 (/doc/stanford/Lecture-1.pdf)
299
300
Captulo S.2
Stanford: Lecture 2
S.2.1 App: Cartas
S.2.2 Objective C
S.2.2.1 Clases
Card
301
Deck
PlayingCard
PlayingCardDeck
S.2.4 Referencias
PDF: Lecture 2 (/doc/stanford/Lecture-2.pdf)
302
Curso iOS 8
Captulo S.3
Stanford: Lecture 3
S.3.1 App: Cartas (continuacin)
Curso iOS 8
S.3.3.2 Editar
No solo cdigo, tambin storyboard, inspectores de atributos...
Ctrl-drag para conectar (actions y outlets).
Click derecho sobre botones para ver conexiones (y desconectar)
Encontrar errores y avisos (y corregirlos)
Depurador
304
Curso iOS 8
S.3.4.2 Propiedades
@property (nonatomic) <type> <property name> (siempre nonatomic en
este curso)
Son solo mtodos setter y getter. Por defecto generados automticamente por el
compilador.
Mejor que variables de instancia solas (lazy instantiation, chequear consistencia,
actualizar UI, etc)
@property (strong or weak) <type which is a pointer to an object>
<property name>
Curso iOS 8
Si un puntero tiene el valor nil (p.ej. 0), significa que el puntero no apunta a nada
S.3.4.4 Mtodos
Declarar y definir mtodos de instancia - (int)match:(NSArray *)otherCards
Declarar y definir mtodos de clase + (NSArray *)validSuits
Invocar mtodos de instancia [myArray addObject:anObject]
Invocar mtodos de clase unsigned int rank = [PlayingCard maxRank]
El nombre del mtodo y sus parametros se intercalan [deck addCard:aCard
atTop:YES]
S.3.4.5 NSString
Inmutable y generalmente creado manipulando otros strings o mediante @"" o
mtodos de clase
Ejemplo: NSString *myString = @"hello"
Ejepmlo: NSString *myString = [otherString
stringByAppendingString:yetAnotherString]
S.3.4.6 NSArray
Inmutable y generalmente creados manipulando otros arrays o mediante "@[]"
@[@"a",@"b"] es igual que [[NSArray alloc] initWithObjects: @"a",
@"b", nil]
Curso iOS 8
S.3.4.9 Otros
Enumeracin rpida: for (MyClass *myObject in arrayOfMyObjects) { }
#define
NSLog(@"show this object %@ in the console", anObject);
S.3.5 Referencias
PDF: Lecture 3 (/doc/stanford/Lecture-3.pdf)
307
308
Captulo S.4
Stanford: Lecture 4
S.4.1 Resumen
S.4.1.1 Objective C
Crear objetos
nil
El superimportante tipo id (y el concepto de dynamic binding)
309
Curso iOS 8
Introspeccin
App: Cartas (mejorar con introspeccin)
S.4.1.2 Foundation
NSObject, NSArray, NSNumber, NSData, NSDictionary, etc
Property Lists y NSUserDefaults
NSRange
UIFont y UIColor (pertenecen a UIKit)
NSAttributedString (y su extensiones en UIKit)
Attributed strings en UITextView y UILabel
Tambin se puede pedir a otros objetos que creen objetos por ti:
- (NSString *)stringByAppendingString:(NSString *)otherString; //
NSString
- (NSString *)componentsJoinedByString:(NSString *)separator; // NSArray
- (id)mutableCopy; // NSString y NSArray
Pero no todos los objetos que nos dan son recin creados:
310
Curso iOS 8
- (id)lastObject; // de NSArray
- (id)objectAtIndex:(int)index; // de NSArray
A no ser que el mtodo tenga la palabra copy, si el objeto ya existe, nos dan un puntero al
mismo. Si el objeto no existe, entonces lo estaremos creando.
S.4.3 nil
Curso iOS 8
Curso iOS 8
S.4.5 Instrospeccin
Todos los objetos que heredan de NSObject implementan estos tres mtodos:
isKindOfClass: devuelve si un objeto es este tipo de class (herencia incluida)
isMemberOfClass: devuelve si un objeto es exactamente este tipo de class (sin
herencia)
respondsToSelector: devuelve si un objeto responde al un mtodo concreto
if ([obj isKindOfClass:[NSString class]]) {
NSString *s = [(NSString *)obj stringByAppendingString:@"xyz"];
}
313
Curso iOS 8
[array makeObjectsPerformSelector:shootSelector];
[array makeObjectsPerformSelector:shootAtSelector withObject:target]; //
target is an id
En un UIButton:
- (void)addTarget:(id)anObject action:(SEL)action ...;
[button addTarget:self action:@selector(digitPressed:) ...];
S.4.6.2 Introspeccin
NSObject es importante porque implementa los mtodos bsicos para la introspeccin.
Los recordamos:
Curso iOS 8
Pero no todos los objetos implementan este mecanismo (saltar una excepcin si se intenta copiarlos y no lo hacen).
S.4.6.3 NSArray
Coleccin ordenada de objetos.
Inmutable. Una vez creado no puedes aadir o eliminar objetos.
Todos los objetos se retienen mediante un puntero strong.
Se crean mediante manipulando otros arrays o mediante @[].
Mtodos que ya conocemos:
- (NSUInteger)count;
- (id)objectAtIndex:(NSUInteger)index; // devuelve un id y hace crash si
el ndice est fuera de lmites
- (id)lastObject; // devulve nil (sin crash) si no hay objetos en el
array
- (id)firstObject; // devulve nil (sin crash) si no hay objetos en el
array
S.4.6.4 NSMutableArray
Versin mutable de NSArray.
Se crean mediante alloc init o bien:
315
Curso iOS 8
+ (id)arrayWithCapacity:(NSUInteger)numItems; // numItems is a
performance hint only
+ (id)array;
[NSMutableArray
init]
alloc]
NSMutableArray hereda todos los mtodos de NSArray. No solo count, objectAtIndex:, etc.
S.4.6.6 NSNumber
Es un objeto para empaquetar tipos primitivos como: int, float, double, BOOL, enums,
etc.
316
Curso iOS 8
Util cuando quieres poner estos tipos primitivos en una coleccin (p.ej. NSArray o NSDictionary)
Hay una nueva sintaxis para crear un NSNumber desde iOS 6: @()
NSNumber
NSNumber
NSNumber
devuelve
*three = @3;
*underline = @(NSUnderlineStyleSingle); // enum
*match = @([card match:@[otherCard]]); // expresin que
un tipo primitivo
S.4.6.7 NSValue
Es un objeto genrico para empaquetar otros datos que no son objetos (p.ej. structs de C)
NSValue *edgeInsetsObject = [NSValue
valueWithUIEdgeInsets:UIEdgeInsetsMake(1,1,1,1)]
S.4.6.8 NSData
Es un saco de bits
Se usa para guardar/restaurar/transmitir datos puros (crudos) por el SDK de iOS.
S.4.6.9 NSDate
Se usa para encapsular fechas. Tambin hay: NSCalendar, NSDateFormatter, NSDateComponents.
317
Curso iOS 8
Los objetos en un set ordenado tienen que ser diferentes. No puedes poner el mismo objeto
en ellos como en un array.
S.4.6.12 NSDictionary
Coleccin inmutable de objetos que se introducen y extraen mediante su clave.
Todas las claves y valores son mantenidas de manera strong por un NSDictionary.
Se pueden crear con esta sintaxis:
@{ key1 : value1, key2 : value2, key3 : value3 }
NSDictionary *colors = @{ @green : [UIColor greenColor],
@blue : [UIColor blueColor],
@red : [UIColor redColor] };
S.4.6.13 NSMutableDictionary
Versin mutable de NSDictionary
Se crean mediante alloc/init o uno de los mtodos de clase
+ (id)dictionary... class methods.
(void)setObject:(id)anObject forKey:(id)key;
(void)removeObjectForKey:(id)key;
(void)removeAllObjects;
(void)addEntriesFromDictionary:(NSDictionary *)otherDictionary;
S.4.6.14 Enumeracin
Pasar por las claves o valores de un diccionario. Ejemplo:
NSDictionary *myDictionary = ...;
for (id key in myDictionary) {
// do something with key here
318
Curso iOS 8
Este mtodo solo se le puede mandar a un NSArray o NSDictionary que sean Property
Lists
Lists.
S.4.6.16 NSUserDefaults
Espacio de almacenamiento ligero para Property Lists
Es bsicamente un diccionario que persiste entre ejecuciones de nuestra aplicacin.
319
Curso iOS 8
Mtodos:
- (void)setDouble:(double)aDouble forKey:(NSString *)key;
- (NSInteger)integerForKey:(NSString *)key;
- (void)setObject:(id)obj forKey:(NSString *)key; // obj debe ser
Property List
- (NSArray *)arrayForKey:(NSString *)key; // devuevle nil si el valor
para esa clave no es un NSArray
S.4.6.17 NSRange
Es una struct de C (no una clase).
Se usa para especificar subrangos dentro de strings y de arrays.
typedef struct {
NSUInteger location;
NSUInteger length;
} NSRange;
Curso iOS 8
NSMakeRange() creacin
S.4.6.18 UIColor
Objeto que representa un color.
Los inicializadores para crear un color estn basadoe en RGB, HSB e incluso una trama
UImage.
Los colores pueden tener transparencia (alpha):
UIColor *color = [otherColor colorWithAlphaComponent:0.3]
Hay una serie de colores con nombre: blanco, rojo, etc y otros como: color de texto, color de
texto claro.
[UIColor
[UIColor
[UIColor
[UIColor
[UIColor
[UIColor
[UIColor
whiteColor];
blackColor];
redColor];
greenColor];
blueColor];
orangeColor];
lightTextColor];
S.4.6.19 UIFont
Representa una fuente de letra.
Con el nuevo estilo de iOS 7 las tipografas son an ms importantes.
Para el contenido del usuario lo mejor es solicitar al sistema las fuentes preferidas del
usuario para los diferentes estilos disponibles:
UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
Otros estilos son: UIFontTextStyleHeadline, UIFontTextStyleCaption1, UIFontTextStyleFootnote, ... (ver documentacin de UIFontDescriptor)
Tambin existen las fuentes de sistema. Se usan preferentemente para los textos propios
de la aplicacin (no los del contenido del usuario).
+ (UIFont *)systemFontOfSize:(CGFloat)pointSize;
+ (UIFont *)boldSystemFontOfSize:(CGFloat)pointSize;
Nunca uses fuentes de sistema para el contenido del usuario (porque el tamao estar predefinido).
321
Curso iOS 8
S.4.6.20 UIFontDescriptor
Las fuente son diseadas por artistas. Y no siempre encajan en las categoras que queremos. Ejemplo:
Una fuente que solo tiene maysculas.
Una fuente en la que no se ha diseado con bold o itlica.
UIFontDescriptor intenta categorizarlas en cualquier caso.
Curso iOS 8
Ms ejemplos de traits:
UIFontDescriptorTraitItalic
UIFontDescriptorTraitBold
UIFontDescriptorTraitCondensed
Once you have a UIFontDescriptor that describes the font you want, use this UIFont method:
(UIFont *)fontWithDescriptor:(UIFontDescriptor *)descriptor size:(CGFloat)size;
(specify size of 0 if you want to use whatever size is in the descriptor)
You will get a best match for your descriptor given available fonts and their faces.
Ejemplo para intentar obtener una bold body font:
UIFont *bodyFont = [UIFont
preferredFontForTextStyle:UIFontTextStyleBody];
UIFontDescriptor *existingDescriptor = [bodyFont fontDescriptor];
UIFontDescriptorSymbolicTraits traits =
existingDescriptor.symbolicTraits;
traits |= UIFontDescriptorTraitBold;
UIFontDescriptor *newDescriptor = [existingDescriptor
fontDescriptorWithSymbolicTraits:traits];
UIFont *boldBodyFont = [UIFont fontWithFontDescriptor:newDescriptor
size:0];
La fuente es importante, pero hay otros atributos: color, si est outlined, ancho del trazo,
subrayado, etc.
S.4.7.1 NSAttributedString
Se puede pensar en ellos como un NSString donde cada letra tiene un NSDictionary de
atributos. Aunque realmente no es una subclase de NSString.
Obtener Atributos
Se puede pedir a un NSAttributedString todos los atributos en un lugar del string.
323
Curso iOS 8
- (NSDictionary *)attributesAtIndex:(NSUInteger)index
effectiveRange:(NSRangePointer)range;
Este mtodo se garantiza que ser rpido, pero el valor es volatil. Si quieres guardar el texto es mejor hacer una copia.
S.4.7.2 NSMutableAttributedString
Al contrario que con NSString, casi siempre usamos esta versin mutable.
Aadir o establecer atributos
Se puede aadir atributos a un rango...
- (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range;
... lo cual cambiar los valores de esos atributos pero no tocar otros.
Se puede establecer los atributos as:
(void)setAttributes:(NSDictionary *)attributes range:(NSRange)range;
... lo cual quitar todos los dems atributos en ese rango.
Tambin se puede eliminar atributos especficos de un rango...
324
Curso iOS 8
S.4.7.3 UILabel
Hasta ahora sabamos establecer su contenido con la propiedad NSString *text
Pero tambin tiene una propiedad para establecer sus texto mediante un NSAttributedString:
@property (nonatomic, strong) NSAttributedString *attributedText;
325
Curso iOS 8
Tambin hay propiedades para establecer el font, textColor, etc. a la vez para todos los caracteres.
S.4.8 Referencias
PDF: Lecture 4 (/doc/stanford/Lecture-4.pdf)
326
Captulo S.5
Stanford: Lecture 5
S.5.1 UITextView
327
Curso iOS 8
S.5.3 NSNotification
S.5.4 Demo
UITextView
NSAttributedString, NSMutableAttributedString, NSTextStorage, UIFont,
UIColor
NSNotification
View Controller Lifecycle
S.5.5 Referencias
PDF: Lecture 5 (/doc/stanford/Lecture-5.pdf)
328
Captulo S.6
Stanford: Lecture 6
S.6.1 Multiple MVCs
329
S.6.2 UINavigarionController
330
Curso iOS 8
Curso iOS 8
S.6.3 UITabBarController
S.6.4 Referencias
PDF: Lecture 6 (/doc/stanford/Lecture-6.pdf)
331
332
Captulo S.7
Stanford: Lecture 7
333
334
Curso iOS 8
Curso iOS 8
S.7.3 Referencias
PDF: Lecture 7 (/doc/stanford/Lecture-7.pdf)
335
336
Captulo S.8
Stanford: Lecture 8
337
S.8.1 Protocolos
S.8.2 Blocks
338
Curso iOS 8
Curso iOS 8
S.8.3 Animaciones
S.8.4 Referencias
PDF: Lecture 8 (/doc/stanford/Lecture-8.pdf)
339
340
Captulo S.9
Stanford: Lecture 9
341
S.9.1 Autolayout
S.9.2 Referencias
PDF: Lecture 9 (/doc/stanford/Lecture-9.pdf)
342
Curso iOS 8
Captulo S.10
Stanford: Lecture 10
S.10.1 Multithreading
343
S.10.2 UIScrollView
Curso iOS 8
Una ventana de contenido tan grande como se quiera, que se puede mover y sobre el que
se puede hacer zoom.
344
Curso iOS 8
S.10.3 UITableView
S.10.4 Referencias
PDF: Lecture 10 (/doc/stanford/Lecture-10.pdf)
345
346
Captulo S.11
Stanford: Lecture 11
347
S.11.1 UITableView
S.11.2 iPad
348
Curso iOS 8
Curso iOS 8
S.11.3 Referencias
PDF: Lecture 11 (/doc/stanford/Lecture-11.pdf)
349
350
Captulo S.12
Stanford: Lecture 12
351
S.12.2 UIManagedDocument
352
Curso iOS 8
Curso iOS 8
S.12.3 NSNotification
S.12.4 Categoras
353
S.12.5 Referencias
PDF: Lecture 12 (/doc/stanford/Lecture-12.pdf)
354
Curso iOS 8
Captulo S.13
Stanford: Lecture 13
355
S.13.2 NSFetchedResultsController
356
Curso iOS 8
Curso iOS 8
S.13.3 CoreDataTableViewController
S.13.4 Referencias
PDF: Lecture 13 (/doc/stanford/Lecture-13.pdf)
357
358
Captulo S.14
Stanford: Lecture 14
359
S.14.1 UIApplication
360
Curso iOS 8
Curso iOS 8
S.14.4 Referencias
PDF: Lecture 14 (/doc/stanford/Lecture-14.pdf)
361
362
Captulo S.15
Stanford: Lecture 15
363
S.15.2 MkAnnotation
364
Curso iOS 8
Curso iOS 8
S.15.3 MkDirections
S.15.4 Referencias
PDF: Lecture 15 (/doc/stanford/Lecture-15.pdf)
365
366
Captulo S.16
Stanford: Lecture 16
367
S.16.2 UITextField
368
Curso iOS 8
Curso iOS 8
S.16.4 Referencias
PDF: Lecture 16 (/doc/stanford/Lecture-16.pdf)
369
370
Captulo S.17
Stanford: Lecture 17
371
372
Curso iOS 8
Curso iOS 8
S.17.4 Referencias
PDF: Lecture 17 (/doc/stanford/Lecture-17.pdf)
373
374
Captulo S.18
Stanford: Lecture 18
375
S.18.1 Internacionalizacin
S.18.2 NSNumberFormatter
376
Curso iOS 8
Curso iOS 8
S.18.3 NSDateFormatter
S.18.4 Referencias
PDF: Lecture 18 (/doc/stanford/Lecture-18.pdf)
377
378
Apndice A
Descargas
A.1 Curso completo
Libro PDF (/descargas/ios.pdf)
Libro EPUB (/descargas/ios.epub)
A.2 Recursos
Iconos.zip (/descargas/Iconos.zip)
AppStore.zip (/descargas/AppStore.zip)
A.3 Apps
A.3.1 500px
Versin 1 (collection bsico) 500px.zip (/descargas/v1/500px.zip)
Versin 2 (detalle, cache, scroll infinito) 500px.zip (/descargas/v2/500px.zip)
A.3.2 CoreData
Versin 1 (bsico) EjemploCoreData.zip (/descargas/v1/EjemploCoreData.zip)
A.3.3 Libros
Recursos: Libros.zip (/descargas/Libros.zip)
379
Apndice A Descargas
Curso iOS 8
A.3.4 Ejemplos
Fechas: EjemploSplitView.zip (/descargas/EjemploSplitView.zip)
Fechas: Fechas.zip (/descargas/Fechas.zip)
Fechas: EjemploMapa.zip (/descargas/EjemploMapa.zip)
Fechas: EjemploWebView.zip (/descargas/EjemploWebView.zip)
A.3.5 Juegos
Tetris.zip (/descargas/Tetris.zip)
A.3.6 Rutas
MapKit: Dibujar rea Parque Natural AreaMapa.zip (/descargas/AreaMapa.zip)
A.3.7 GCD
GCD: Descarga asncrona de fotos GCD.zip (/descargas/GCD.zip)
A.3.8 Cervezas
Lista y fotos Cervezas.zip (/descargas/Cervezas.zip)
App iPhone con edicin, borrado, persistencia y picker de fotos Cervezas2.zip
(/descargas/Cervezas2.zip)
A.3.10 Happy
CoreDraw: Happy.zip (/descargas/Happy.zip)
Protocolos y delegacin: HappyDelegate.zip (/descargas/HappyDelegate.zip)
A.3.11 Cuestionario
Cuestionario.zip (/descargas/Cuestionario.zip)
380
Curso iOS 8
Apndice A Descargas
A.4 Ejemplos
Blocks.zip (/descargas/Blocks.zip)
SplitView.zip (/descargas/SplitView.zip)
Popover.zip (/descargas/Popover.zip)
Alertas.zip (/descargas/Alertas.zip)
UIWebView.zip (/descargas/UIWebView.zip)
UIScrollView.zip (/descargas/UIScrollView.zip)
Table.zip (/descargas/Table.zip)
381