iOS Avanzado
Transcript of iOS Avanzado
![Page 1: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/1.jpg)
Repaso 1
![Page 2: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/2.jpg)
QUE NECESITO PARA HACER UNA APP IOS
Hardware Software Conocimiento Ideas Tiempo
![Page 3: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/3.jpg)
HARDWARE NECESARIO
Mínimo
Recomendado
![Page 4: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/4.jpg)
SOFTWARE NECESARIO
Mínimo
Recomendado
SDK PIXELMATOR SMULTRON
SDK PHOTOSHOP DREAMWEAVER SMARTSVN NAVICAT
![Page 5: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/5.jpg)
CONOCIMIENTO NECESARIO PARA HACER APPS
Diseño gráfico y de interfacesObjective - CCocoaQuartzC/C++OpenGL ES 1.5/2.0GLSLHTML5JavascriptCSSPHPSQLiteMySQL
![Page 6: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/6.jpg)
¿QUE VAMOS A APRENDER EN ESTE CURSO?
Objective CCocoaQuartz
HTML5Javascript
CSS
OpenGL ES 1.5OpenGL ES 2.0
GLSL
PHPMySQLSQLite
![Page 7: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/7.jpg)
1.Introducción
- Vamos a crear una aplicación de ejemplo y repasaremos algunos aspectos básicos
- Daremos un repaso a Objective - C
- Gestión de memoria con ARC
- Delegation and Core Location
![Page 8: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/8.jpg)
2.Patrones básicos en cocoa: Patrón MVC
El modelo-vista-controlador es un patrón arquitectónico. Se emplea para estructurar las interfaces de los programas de una manera en la que separamos tareas diferentes en diferentes capas. Por un lado tenemos la presentación, por otro la lógica de aplicación y por otro la información del dominio.
![Page 9: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/9.jpg)
2.Patrones básicos en cocoa: Delegation
El mecanismo de delegados consiste en que un clase A implementa l o s métodos de o t r a c l a se B pa r a hace r se ca r go de l comportamiento de esta, cuando esos métodos son llamados. El objeto A se llama delegado de B
![Page 10: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/10.jpg)
3.Aplicación de ejemplo
- Ver diferentes templates de proyectos XCode- Iconos- Imágenes de Lanzamiento- Cómo creamos las interfaces desde Interface Builder- Declaración de variables- Declaración de métodos - Creando conexiones de variables y objetos de IB- Enlazando objetivos y acciones- Ejecución en el simulador- Ejecución en el dispositivo- Debugger- Instruments
![Page 11: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/11.jpg)
4.Gestión de vistas
- Las diferentes vistas se gestionan como diferentes capas, pudiendo superponer unas a otras y soportando transparencias.
![Page 12: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/12.jpg)
5.Ciclo de vida
Delegate Controlador Vista
Inicio
Fin
Botón {Preferencias()}
Inicio {AbrirTitulo()}
AbrirPreferencias() Preferencias()
AbrirTitulo()
![Page 13: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/13.jpg)
6.Objective-C
- Objective-C es una extensión del lenguaje C
- Las aplicaciones iOS se desarrollan utilizando Objective-C y las librerías de Cocoa Touch
- Cocoa Touch está escrito en Objective-C y es un conjunto de APIs que nos permiten programar las aplicaciones
![Page 14: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/14.jpg)
6.Clases
Coche
int numRuedas; //Atributo
-(int) getNumRuedas; //Método-(void) setNumRuedas:(int)n;
- Clase: Define una estructura y comportamiento.- Objeto: Es una instancia a una clase.- Atributo: Propiedad de una clase.- Método: Define un comportamiento- Evento: Interacción del usuario con la máquina.- Mensaje: comunicación dirigida a un objeto ordenándole que ejecute uno de sus métodos.
![Page 15: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/15.jpg)
7.Instancias
Para crear una instancia de una clase primero debemos pedir memoria
NSMutableArray *listaPersonas = [NSMutableArray alloc];
Pero para ser usado ese objeto, necesita ser inicializado, para ello llamaremos a su método constructor.
[listaPersonas init];
Se suele usar mediante llamadas anidadas:
NSMutableArray *listaPersonas = [[NSMutableArray alloc] init];
![Page 16: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/16.jpg)
8.Mensajes
- Mensaje : Comunicación dirigida a un objeto para que ejecute uno de sus métodos
NSMutableArray *listaPersonas = [[NSMutableArray alloc] init]; [listaPersonas addObject:@""];
![Page 17: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/17.jpg)
9.Listas y bucles
- NSMutableArray es como NSArray pero la gestión de memoria es dinámica, podemos añadir y quitar elementos y el compilador gestionará el tamaño en memoria de la lista
NSMutableArray *listaPersonas = [[NSMutableArray alloc] init]; [listaPersonas addObject:@"Carlos"]; [listaPersonas addObject:@"David"]; [listaPersonas addObject:@"Juan"]; for (int i=0;i<[listaPersonas count];i++) { NSLog(@"Posición %d de la lista es %@",i,[listaPersonas objectAtIndex:i]); }
- Usamos NSArray para crear listas de objetos. NSArray tiene un tamaño fijo, como una constante, definida cuando se crea
![Page 18: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/18.jpg)
10.NSString
- NSString es una clase de Objective-C usada para representar cadenas.
NSString *cadena1 = @"Reserva de memoria implícita"; NSString *cadena2 = [[NSString alloc] initWithString:@"Reserva de memoria con reference counting"];[cadena2 release]; NSString *cadena3 = [[[NSString alloc] initWithString:@"Reserva de memoria autorelease"] autorelease];
![Page 19: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/19.jpg)
11.Heredar de una clase
- Todas las clases de Objective-C tiene una superclase, excepto NSObject
- Una clase hereda el comportamiento de su superclase
![Page 20: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/20.jpg)
12.Variables y métodos de instancia
@interface Persona : NSObject { NSString *nombre; NSString *dni; int edad;}
@property (nonatomic, retain) NSString *nombre;@property (nonatomic, retain) NSString *dni;@property (nonatomic) int edad;
@end
- Para acceder a las variables de instancia hace falta tener una instancia de esa clase.
![Page 21: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/21.jpg)
12.Variables y métodos de instancia
Propiedades: @property (atributos) tipo nombre;
Lectura/escritura: - readwrite: opción por defecto en la definición de las propiedades, y permite que se pueda leer y escribir su contenido. - readonly: Esta opción indica que la propiedad es solo de lectura.
Tipo de asignación: - assign: opción por defecto. Se realiza la asignación sin invocar a retain. Este tipo se suele utilizar para propiedades de tipos que no son objetos. - retain: Se realiza la asignación invocando a retain. Este tipo solo se puede utilizar para objetos. - copy: se le asigna a la propiedad una copia del objeto pasado al setter.
![Page 22: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/22.jpg)
12.Variables y métodos de instancia
Atomicidad: - atomic: es la opción por defecto y su función es bloquear la asignación para que ningún hilo pueda modificar la propiedad mientras lo está haciendo otro hilo. - nonatomic: en esta opción no hay bloqueo, por lo que cualquier hilo puede modificar el valor sin tener que esperar a que termine el otro.
Métodos para acceder: - getter=nombre: por defecto, si no se indica nada, el getter tendrá el mismo nombre que el identificador de la propiedad. Por ejemplo: getName. - setter=nombre: por defecto, si no se indica nada, el setter tendrá como nombre al identificador de la propiedad precedido de la palabra set. Por ejemplo: setName.
![Page 23: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/23.jpg)
13.Métodos de clase vs métodos de instancia
Método estático de la clase:
+ (tipo) nombre; + (tipo) nombre:(tipo)param1 ... nombreArgN:(tipo)paramN;
Método de la clase:
- (tipo) nombre; - (tipo) nombre:(tipo)param1 ... nombreArgN:(tipo)paramN;
![Page 24: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/24.jpg)
14.Gestión de memoria
Implícito
NSString *cadena = [NSString stringWithString:@”Hola”]; //sin alloc
Manual
alloc +1retain +1release -1
NSString *cadena = [[NSString alloc] initWithString:@”Hola”];[cadena release];
Automático
NSString *cadena = [[NSString alloc] initWithString:@”Hola”];[cadena autorelease];
![Page 25: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/25.jpg)
15.Gestión de memoria con ARC
- ARC: Automatic Reference Counting
- Evitamos tener que liberar memoria de forma manual y el tiempo que perdemos buscando memory leaks.
- ARC es un paso de pre-compilación que añade retain/release/autorelease sin tener que añadirlo manualmente.
- A pesar de eso, no nos podemos olvidar de la gestión de memoria por completo.
![Page 26: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/26.jpg)
15.Gestión de memoria con ARC
![Page 27: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/27.jpg)
15.Gestión de memoria con ARC
- Cuando habilitamos ARC nuestro código queda de la siguiente manera:
NSObject *obj = [[NSObject alloc] init];
- Esto no significa que el contador de referencias desaparezca, sino que es automático.
- Cuando el precompilador considera que el objeto no se va a usar más, añade automáticamente una línea para liberar ese objeto:
[obj release];
![Page 28: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/28.jpg)
16.Referencias fuertes
Se utiliza el atributo strong.
Especifica que hay una relación de propiedad (fuerte) sobre el objeto de destino.
Sin ARC:@property(retain) NSObject *obj;
Con ARC:@property(strong) NSObject *obj;
@property(weak) NSObject *obj;
![Page 29: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/29.jpg)
17.Referencias débiles
Se utiliza el atributo weak.
Especifica que hay una relación de no-propiedad (débil) sobre el objeto de destino. Contamos con la ventaja de que si el objeto en cuestión resulta desalojado de la memoria (dealloc), entonces el valor de la propiedad se ajustará automáticamente a nil y, por tanto, en ningún caso se producirá un cuelgue del programa dado que el lenguaje permite enviar mensajes a nil.
![Page 30: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/30.jpg)
Repaso 2
![Page 31: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/31.jpg)
1.Introducción
- Cadenas- Propiedades comunes de los objetos- Labels- Imágenes- Slider- AlertView- MapKit- Text Input- UIView- UIScrollView- UIWebView- Múltiples controladores - AppDelegate
![Page 32: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/32.jpg)
2.Cadenas
Componemos la cadena con el texto de los labels y textfields
! NSString *cadena = [[NSString alloc] initWithString:@"La cadena es : "];! cadena = [cadena stringByAppendingFormat:label1.text];! cadena = [cadena stringByAppendingFormat:textField1.text];!! cadena = [cadena stringByAppendingFormat:label2.text];! cadena = [cadena stringByAppendingFormat:textField2.text];! !
![Page 33: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/33.jpg)
3.Propiedades comunes de los objetos
UIView *objeto = [[UIView alloc] initWithFrame:CGRectMake:(0,0,300,300)];
Posición: [objeto setCenter:CGPointMake(30,30)];
Tamaño: [objeto setBounds:CGRectMake(0,0,300,300)];
Transparencia: [objeto setAlpha:0.5];
Hidden: [objeto setHidden:TRUE];
...
![Page 34: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/34.jpg)
4.Label
Cambiar texto de un UILabel:
[label setText:@”Texto deseado”];
![Page 35: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/35.jpg)
5.Imágenes
Instanciar UIImageView y añadirlo a la vista
UIImageView *imagen = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,100,100)]; [imagen addSubview:self.view];
Cambiar imagen de un UIImageView:
UIImage *im = [UIImage imageNamed:@”imagen.jpg”];imagen.image=im;
![Page 36: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/36.jpg)
6.Slider
Método que se invocará cuando el slider cambie de valor
-(IBAction)valueChange:(id)sender{! int valor = (int)slider.value;! NSString *cadena = [NSString stringWithFormat:@"El valor es %d",valor];! [label setText:cadena];}
Configuración del slider en la carga de la vista
- (void)viewDidLoad { [slider setMinimumValue:1.0];! [slider setMaximumValue:10.0];! [slider setValue:5.0]; [super viewDidLoad];}
![Page 37: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/37.jpg)
7.UISegmentedControl
Detectar cambio en un UISegmentedControl.
- (IBAction)segmentAction:(id)sender{! switch ([sender selectedSegmentIndex]) !{! ! case 0: //Hacer algo para la primera pestaña! ! ! break;! ! case 1: //Hacer algo para la primera pestaña! ! ! break;! }}
![Page 38: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/38.jpg)
8.AlertView
Mostramos un AlertView
UIAlertView *alert = [[UIAlertView alloc]! ! ! initWithTitle: @"Titulo"! ! ! message: @"Texto aquí"! ! ! delegate: nil! ! ! cancelButtonTitle:@"OK"! ! ! otherButtonTitles:nil];
[alert show];[alert release];
![Page 39: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/39.jpg)
9.MapKit
Configuración del mapa en la carga de la vista
- (void)viewDidLoad {!! [mapa setMapType:MKMapTypeHybrid]; ! [mapa setZoomEnabled:YES]; ! [mapa setScrollEnabled:YES]; ! [mapa setShowsUserLocation:YES];!! [super viewDidLoad];}
Debemos añadir los frameworks de MapKit
![Page 40: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/40.jpg)
10.Text Input
- Cajas de introducir texto, permiten seleccionar diferentes tipos de teclados
- Para liberar teclado implementar el protocolo UITextFieldDelegate y sobreescribir el método de su delegado
- (BOOL)textFieldShouldReturn:(UITextField *)tf{ [tf resignFirstResponder]; return YES;}
![Page 41: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/41.jpg)
11.UIView
- Uno de los elementos más usados
- Podemos tener vistas dentro de otras vistas de manera jerárquica
- Podemos sobreescribir el método drawRect para que la vista pinte algo específico
![Page 42: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/42.jpg)
12.UIScrollView
- Crearemos una app de tipo Single View Application
- Crear un UIScrollView programáticamente y añadirlo a la vista
- Implementar UIScrollViewDelegate en nuestro controlador
- Crear un UIImageView y asignarle una imagen, añadirlo al UIScrollView
- Sobreescribir los métodos adecuados para que nos permita hacer zoom sobre la imagen
![Page 43: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/43.jpg)
12.UIScrollView
- Creación y ajuste de elementos
//Instanciar ScrollView sv = [[UIScrollView alloc] initWithFrame: CGRectMake(0,0,self.view.bounds.size.width, self.view.bounds.size.height)]; [self.view addSubview:sv]; [sv release]; //Instanciar UIImageView iv = [[UIImageView alloc] initWithFrame: CGRectMake(0,0,self.view.bounds.size.width*2, self.view.bounds.size.height*2)]; [sv addSubview:iv]; [iv release]; //Asignar propiedades UIImageView [iv setImage:[UIImage imageNamed:@"wallpaper.jpg"]]; //Asignar propiedades UIScrollView [sv setContentSize:CGSizeMake(iv.bounds.size.width, iv.bounds.size.height)]; [sv setMinimumZoomScale:0.5]; [sv setMaximumZoomScale:2.5]; [sv setZoomScale:1.0 animated:TRUE]; [sv setDelegate:self];
![Page 44: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/44.jpg)
12.UIScrollView
- Devolver vista sobre la que se realizará zoom
-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView{ return iv;}
![Page 45: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/45.jpg)
13.UIWebView
Cargar web en un UIWebView
-(IBAction)irAPagina:(id)sender{ ! //Obtain the url! NSString *urlAddress = textField.text;!! //Create an NSURL Object! NSURL *url = [NSURL URLWithString:urlAddress];!! //URL Request Object! NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];!! //Load the request in the UIWebView.! [webView loadRequest:requestObj];}
![Page 46: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/46.jpg)
14.UITabBar
Seleccionar tabButton
//Seleccionar el primer elemento [tabBar setSelectedItem:[tabBar.items objectAtIndex:0]]; Recoger pulsación
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {! switch (item.tag) {! ! case 0:! ! ! //Pestaña1! ! ! break;! ! case 1:! ! ! //Pestaña2! ! ! break;! }! ! !}
![Page 47: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/47.jpg)
15.Múltiples controladores
Cargar un controlador y añadirlo a una vista
! controlador1=[[Controlador1 alloc] initWithNibName:@"Controlador1" bundle:nil]; ! [vistaControladores addSubview:controlador1.view];
Quitar la vista de un controlador y liberarlo
[controlador1.view removeFromSuperview]; [controlador1 release]; controlador1=nil;
![Page 48: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/48.jpg)
16.AppDelegate
#import “ClaseD.h”
ClaseD *mainDelegate = (ClaseD*) [[UIApplication sharedApplication] delegate];
[mainDelegate cambiarAVista2];
- Para controlar el ciclo de vida utilizaremos el AppDelegate.
- En AppDelegate instanciaremos nuevos controladores y eliminaremos los que no usemos.
- Desde los controladores podremos acceder al AppDelegate para invocar un método
![Page 49: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/49.jpg)
Repaso 3
![Page 50: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/50.jpg)
1.Introducción
- UITableView y UITableViewController- Edición de UITableView- UINavigationController- UIPopoverController - Vistas Modales
![Page 51: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/51.jpg)
2.UITableView
- Podemos trabajar con este elemento haciendo subclassing de UITableViewController o i m p l e m e n t a n d o e l d e l e g a t e d e UITableViewControllerDelegate en otro controlador
- Vamos a crear un Single View Application
- Mostrar una lista de los meses en un UITableView
![Page 52: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/52.jpg)
2.UITableView
- Implementar el protocolo UITableViewDelegate en nuestro controlador
- Escribir los métodos del delegate
- Rellenar array
lista = [[NSMutableArray alloc] initWithCapacity:12]; [lista addObject:@"Enero"]; [lista addObject:@"Febrero"]; [lista addObject:@"Marzo"]; [lista addObject:@"Abril"]; [lista addObject:@"Mayo"]; [lista addObject:@"Junio"]; [lista addObject:@"Julio"]; [lista addObject:@"Agosto"]; [lista addObject:@"Septiembre"]; [lista addObject:@"Octubre"]; [lista addObject:@"Noviembre"]; [lista addObject:@"Diciembre"];
![Page 53: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/53.jpg)
2.UITableView
- Métodos para rellenar contenido
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [lista count];}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"]; if (!cell) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"] autorelease]; }
[[cell textLabel] setText:[lista objectAtIndex:indexPath.row]]; return cell;}
![Page 54: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/54.jpg)
2.UITableView
- Método para modo de editar
- (IBAction)toggleEditingMode:(id)sender{ if ([tableView isEditing]) { [sender setTitle:@"Editar"]; [tableView setEditing:NO animated:YES]; } else { [sender setTitle:@"Hecho"]; [tableView setEditing:YES animated:YES]; }}
![Page 55: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/55.jpg)
2.UITableView
- Método para mover celdas
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { if (fromIndexPath.row == toIndexPath.row) { return; }
//Quitamos elemento de posición from NSString *e1 = [lista objectAtIndex:fromIndexPath.row]; [e1 retain]; [lista removeObjectAtIndex:fromIndexPath.row]; //Lo añadimos a posición to [lista insertObject:e1 atIndex:toIndexPath.row]; [e1 release];}
![Page 56: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/56.jpg)
2.UITableView
- Método para eliminar celdas
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { //Eliminamos el elemento del array [lista removeObjectAtIndex:indexPath.row]; //Y del tableView con una animación [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; }}
![Page 57: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/57.jpg)
2.UITableView
- Método para cuando seleccionemos una celda
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ NSLog(@"Ha seleccionado el mes %@",[lista objectAtIndex:indexPath.row]);}
![Page 58: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/58.jpg)
3.UINavigationController
- Cambiemos algo de código en AppDelegate para añadir un UINavigationController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch.
UIViewController *vc = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease]; self.window.rootViewController = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease]; [self.window makeKeyAndVisible]; return YES;}
![Page 59: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/59.jpg)
3.UINavigationController
- Configurar barra de navegación
//Poner título[self.navigationItem setTitle:@"Meses"]; //Añadir botón editarUIBarButtonItem *editar = [[UIBarButtonItem alloc] initWithTitle:@"Editar" style:UIBarButtonItemStylePlain target:self action:@selector(toggleEditingMode:)];
self.navigationItem.rightBarButtonItem = editar;[editar release];
![Page 60: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/60.jpg)
4.UIPopoverController
- Vamos a hacer un nuevo ejemplo pa r a iPad y u sa remos un UIPopoverController, que sólo está disponible en estos dispositivos y no en iPhone e iPod Touch
- Crear proyecto Single View Application
- Añadir otro controlador y programarlo con la vista que queramos mostrar
![Page 61: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/61.jpg)
4.UIPopoverController
1. Implementar protocolo UIPopoverControllerDelegate
2. Crear puntero en la cabecera de nuestro controlador
UIPopoverController *mesesPopover;
3. Escribir métodos del delegate UIPopoverController
4. Invocar popOver cuando corresponda
![Page 62: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/62.jpg)
4.UIPopoverController
- Método del delegate
- Nos permitirá responder al evento de cerrar esta vista modal
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController{ [popOver autorelease]; popOver = nil;}
![Page 63: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/63.jpg)
4.UIPopoverController
- Método que lo despliega
-(IBAction)verPopover:(id)sender{ if (popOver==nil) { Otro *otro = [[[Otro alloc] initWithNibName:@"Otro" bundle:nil] autorelease];
popOver = [[UIPopoverController alloc] initWithContentViewController:otro]; [popOver setDelegate:self]; [popOver presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } else { [popOver dismissPopoverAnimated:YES]; [popOver autorelease]; popOver = nil; }
}
![Page 64: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/64.jpg)
5.Vistas Modales
- Las vistas modales son ViewControllers predefinidos que nos proporciona el sistema y que nos permiten hacer cosas habituales como seleccionar una foto, enviar un mail, elegir un contacto, etc..
![Page 65: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/65.jpg)
5.Vistas Modales
- En nuestro ejemplo vamos a añadir un botón nuevo que nos permita enviar un mail
1. Implementar el protocolo
MFMailComposeViewControllerDelegate
2. Añadir el framework
MessageUI.framework#import <MessageUI/MessageUI.h>#import <MessageUI/MFMailComposeViewController.h>
3. Sobreescribir mensajes del delegate implementado
4. Crear mensaje lanzador
![Page 66: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/66.jpg)
5.Vistas Modales
- Sobreescribir método del delegate implementado
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {!! [self dismissModalViewControllerAnimated:YES];}
- Nos permitirá responder al evento de cerrar esta vista modal
![Page 67: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/67.jpg)
5.Vistas Modales
- Invocar vista modal
Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));! if (mailClass != nil)!{! ! if ([mailClass canSendMail]) {! ! ! MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];! ! ! picker.mailComposeDelegate = self;! ! ! picker.navigationBar.barStyle = UIBarStyleBlack;! ! !! ! ! [picker setSubject:@"Título del mensaje"];! ! !! ! ! // Añadir destinatarios por defecto! ! ! NSArray *toRecipients = [NSArray arrayWithObject:@"[email protected]"]; ! ! !! ! ! [picker setToRecipients:toRecipients];! ! !! ! ! // Rellenar contenido del mail por defecto! ! ! NSString *emailBody = @"Introduce aquí tu texto...";! ! ! [picker setMessageBody:emailBody isHTML:NO];! ! !! ! ! [self presentModalViewController:picker animated:YES];! ! ! [picker release];!!! ! } ! }
![Page 68: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/68.jpg)
Repaso 4
![Page 69: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/69.jpg)
1.Introducción
- Notification and Rotation- Camera- Settings- Localization- Multitarea- Gestures- Animaciones- Transiciones predefinidas entre vistas
![Page 70: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/70.jpg)
2.Notification and Rotation- Usaremos notificaciones para atender a ciertos eventos, como por ejemplo la rotación del dispositivo
// Obtener el objeto dispositivo UIDevice *device = [UIDevice currentDevice]; // Empezar a monitorizar notificaciones que tengan que ver con la orientación [device beginGeneratingDeviceOrientationNotifications];
//Añadir notificación y asignarle un método NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:device];
- (void)orientationChanged:(NSNotification *)note{ NSLog(@"orientationChanged: %d", [[note object] orientation]);}
- Método manejador
Texto
![Page 71: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/71.jpg)
3.Camera
- Crearemos un programa que tome una foto de la biblioteca y la asigne en un UIImageView sobre la pantalla
![Page 72: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/72.jpg)
3.Camera
- Implementar el protocolo UIImagePickerControllerDelegate
- Obtener foto
-(IBAction)tomarFoto:(id)sender{ //Instanciar controlador UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { [imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera]; } else { [imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]; }
//Asignar la vista actual como delegate y presentarlo [imagePicker setDelegate:self]; [self presentModalViewController:imagePicker animated:YES]; [imagePicker release]; }
![Page 73: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/73.jpg)
3.Camera- Obtener foto seleccionada
- (void)imagePickerController:(UIImagePickerController *)pickerdidFinishPickingMediaWithInfo:(NSDictionary *)info{ //Obtener la imagen y asignarla a un UIImageView UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; [imagen setImage:image]; [self dismissModalViewControllerAnimated:YES];}
![Page 74: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/74.jpg)
4.Settings
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
standardUserDefaults setObject:@”Hola” forKey:@"clave"];
[standardUserDefaults synchronize]; !
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *cadena = [[standardUserDefaults objectForKey:@”clave”] retain];
- Guardar preferencias
- Cargar preferencias
![Page 75: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/75.jpg)
5.Localization - XIBs
- Creamos nuevo proyecto Single View Application
- Añadimos algunos labels y otros elementos a la vista
- Después añadimos a la localización de la vista el idioma Español
- Desde la consola usaremos el comando ibtool para generar el fichero de cadenas a partir de nuestro xib
ibtool --generate-strings-file ~/Desktop/ViewController.strings ViewController.xib
- Ese comando genera un fichero con el siguiente contenido:
/* Class = "IBUILabel"; text = "Texto del label"; ObjectID = "8"; */"8.text" = "Texto del label";
/* Class = "IBUINavigationItem"; title = "Titulo de la vista"; ObjectID = "10"; */"10.title" = "Titulo de la vista";
![Page 76: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/76.jpg)
5.Localization - XIBs
- Editamos el fichero para asignar los valores del idioma al que vamos a traducir
/* Class = "IBUILabel"; text = "Texto del label"; ObjectID = "8"; */"8.text" = "Label text";
/* Class = "IBUINavigationItem"; title = "Titulo de la vista"; ObjectID = "10"; */"10.title" = "Title of the view";
- Ahora usamos ibtool para crear un nuevo Xib basado en nuestro xib anterior
ibtool --strings-file ~/Desktop/ViewController.strings --write ../es.lproj/ViewController.xib ViewController.xib
- Esto nos modifica el XIB cuando ese idioma sea el de por defecto utilizando los valores del fichero de texto
![Page 77: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/77.jpg)
5.Localization - Código
- Para localizar el código de la aplicación utilizaremos la macro NSLocalizedString
- Vamos a crear un label dinámicamente y queremos que esté localizado
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0,0,100,20)];[self.view addSubview:label]; [label setText: NSLocalizedString(@"Label añadida",@"El texto de la label que añadimos") ];
- Desde la consola usaremos el comando
$ genstrings ViewController.m
![Page 78: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/78.jpg)
5.Localization - Código
- Ese comando nos genera el fichero Localizable.strings que contiene lo siguiente
/* El texto de la label que añadimos */"Label añadida" = "Label añadida";
- Lo modificamos
/* El texto de la label que añadimos */"Label añadida" = "Label added";
- Añadimos el fichero Localizable.strings a nuestro proyecto
- Si ejecutamos la app en el idioma al que hemos traducido, saldrá localizada, ya que NSLocalizedString lee el fichero Localizable.strings
![Page 79: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/79.jpg)
6.Multitarea
- Controlamos la multitarea mediante la implementación de ciertos métodos en el AppDelegate de nuestras aplicaciones
![Page 80: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/80.jpg)
7.Gestures
• UITapGestureRecognizer - Toque
• UIPinchGestureRecognizer - Zoom
• UIRotationGestureRecognizer - Rotar
• UISwipeGestureRecognizer - Arrastrar izquierda o derecha
• UIPanGestureRecognizer - Mover
• UILongPressGestureRecognizer - Pulsación larga
- Podemos definir ciertos comportamiento para los gestos que registra una vista mediante Gesture Recognizers
![Page 81: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/81.jpg)
7.Gestures
- La forma de trabajar con gestures es la siguiente:
1. Implementar protocolo UIGestureRecognizerDelegate
2. Crear el gesture regognizer y añadirlo a la vista
-(void)swipeRightAction:(UIPanGestureRecognizer*)gestureRecognizer{ //METER CÓDIGO}
3. Crear método que se encarga de recoger el evento cuanto se produce ese gesto sobre la vista
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRightAction:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;swipeRight.delegate = self;[self.view addGestureRecognizer:swipeRight];![swipeRight release];
![Page 82: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/82.jpg)
8.Animaciones
//DEFINIR PROPIEDADES INICIALES
imagen.alpha=1;
[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:0.5];[UIView setAnimationDelegate:self];
!//DEFINIR PROPIEDADES FINALES!imagen.alpha=0;
[UIView commitAnimations];
- Crear una interpolación en el valor de las propiedades de un objeto
![Page 83: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/83.jpg)
9.Transiciones predefinidas entre vistas
[primerControlador.view removeFromSuperview];[primerControlador release];primerControlador=nil;
[UIView beginAnimations:nil context:NULL];[UIView setAnimationDuration:1.0];[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.window cache:YES];! segundoControlador = [[SegundoControlador alloc] initWithNibName:@"SegundoControlador" bundle:nil];! [self.window addSubview:segundoControlador.view];[UIView commitAnimations];
- Eliminar primer controlador, instanciar segundo y indicar transición
![Page 84: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/84.jpg)
9.Transiciones predefinidas entre vistas
Posibles transiciones entre vistas:
UIViewAnimationTransitionCurlUpUIViewAnimationTransitionCurlDownUIViewAnimationTransitionFlipFromLeftUIViewAnimationTransitionFlipFromRigth
![Page 85: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/85.jpg)
19.Touch Events and UIResponder
![Page 86: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/86.jpg)
- Elementos como UIScrollView permiten hacer eventos multitáctiles pero su comportamiento está predefinido.
- Usaremos Touch Events cuando queramos un comportamiento específico.
- En este apartado crearemos una vista sobre la que poder pintar usando las características multitouch de los dispositivos.
- Utilizaremos el gesto doble-tap para limpiar la pantalla
1.Touch Events
![Page 87: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/87.jpg)
- Heredando de UIResponder podremos sobreescribir cuatro métodos para capturar los distintos eventos:
1.Touch Events
Uno o varios dedos tocan la pantalla:- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
Uno o varios dedos se mueven por la pantalla:- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
Uno o varios dedos son retirados de la pantalla:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
El sistema interrumpe este movimiento antes de que termine por una llamada u otro evento:- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
![Page 88: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/88.jpg)
- Podemos tocar y arrastrar sobre la pantalla y arrastrar para dibujar una linea
- Con doble-tap limpiamos la pantalla
2.Creating the TouchTracker Application
![Page 89: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/89.jpg)
- Crear proyecto de tipo Single View Application
- Crear objeto Line de tipo NSObject
- Crear objeto TouchDrawView de tipo NSObject y personalizarlo para que herede de UIView
- Asociar un objeto de tipo UIView de ViewController.xib en interface builder con nuestra clase TouchDrawView
- Sobreescribir los métodos de dibujado en TouchDrawView
- Sobreescribir los métodos de toques en TouchDrawView
2.Creating the TouchTracker Application
![Page 90: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/90.jpg)
Line.h
#import <Foundation/Foundation.h>
@interface Line : NSObject {CGPoint begin;CGPoint end;
}@property (nonatomic) CGPoint begin;@property (nonatomic) CGPoint end;@end
Line.m
#import “Line.h”
@implementation Line
@synthesize begin,end;
@end
2.Creating the TouchTracker Application
![Page 91: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/91.jpg)
TouchDrawView.h
#import <Foundation/Foundation.h>
@interface TouchDrawView : UIView{ NSMutableArray *lines; CGPoint lineInProgressBegin; CGPoint lineInProgressEnd;}
@end
2.Creating the TouchTracker Application
![Page 92: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/92.jpg)
TouchDrawView.m
#import “TouchDrawView.h”#import “Line.h”
@implementation TouchDrawView
-(id)initWithCoder:(NSCoder*)c{ self = [super initWithCoder:c]; if (self) { lines = [[NSMutableArray alloc] init]; lineInProgressBegin = CGPointMake(0,0); lineInProgressEnd = CGPointMake(0,0); [self setMultipleTouchEnabled:FALSE]; } return self;}
-(void)dealloc{ [lines release]; [super dealloc];}
2.Creating the TouchTracker Application
![Page 93: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/93.jpg)
- Sobreescribir el método drawRect para dibujar lo que queramos sobre la vista.
3.Drawing with TouchDrawView
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 10.0); CGContextSetLineCap(context, kCGLineCapRound); // Lineas completas en negro [[UIColor blackColor] set]; for (Line *line in lines) { CGContextMoveToPoint(context, [line begin].x, [line begin].y); CGContextAddLineToPoint(context, [line end].x, [line end].y); CGContextStrokePath(context); } // Linea en progreso en rojo [[UIColor redColor] set]; if (!CGPointEqualToPoint(lineInProgressBegin,lineInProgressEnd)){ CGContextMoveToPoint(context, lineInProgressBegin.x, lineInProgressBegin.y); CGContextAddLineToPoint(context, lineInProgressEnd.x, lineInProgressEnd.y); CGContextStrokePath(context); }}
![Page 94: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/94.jpg)
- Hacer el método de limpiar
3.Drawing with TouchDrawView
- (void)clearAll { // Borrar la lineas [lines removeAllObjects]; // Redibujar [self setNeedsDisplay];}
![Page 95: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/95.jpg)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ //Capturamos el evento del primer dedo detectado UITouch *t = [touches anyObject]; if ([t tapCount] > 1) { [self clearAll]; } else { //Inicializamos el comienzo y el final de la linea lineInProgressBegin = [t locationInView:self]; lineInProgressEnd = lineInProgressBegin; // Redibujar [self setNeedsDisplay]; }}
4.Turning Touch into Lines
![Page 96: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/96.jpg)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *t = [touches anyObject];
//Actualizamos el final de la linea lineInProgressEnd = [t locationInView:self];
// Redibujar [self setNeedsDisplay];}
4.Turning Touch into Lines
![Page 97: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/97.jpg)
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ //Creamos un objeto de tipo linea y
//le asignamos los valores de nuestra linea en progreso Line *linea = [[Line alloc] init]; linea.begin=lineInProgressBegin; linea.end=lineInProgressEnd; //Añadimos dicho objeto a la lista de lineas [lines addObject:linea]; //Reiniciar linea en progreso lineInProgressBegin = CGPointMake(0,0); lineInProgressEnd = CGPointMake(0,0); // Redibujar [self setNeedsDisplay];}
4.Turning Touch into Lines
![Page 98: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/98.jpg)
5.The Responder Chain
UIResponder no maneja el evento porque al no estar sobrescritos sus métodos entonces envía el evento al siguiente respondedor.
Mandar mensaje explícitamente al siguiente respondedor:[[self nextResponder] touchesBegan:touches withEvent:event];
![Page 99: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/99.jpg)
- Crear dos botones, uno de Save y otro de Load en nuestra vista y asociarlos a dos métodos que implementaremos
6.Saving and Loading
-(IBAction)save:(id)sender{ NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:lines]; [prefs setObject:data forKey:@"Lineas"]; [prefs synchronize];}
- Para poder utilizar el método archiveDataWithRootObject es necesario que implementemos en nuestro objeto Line algunos métodos
![Page 100: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/100.jpg)
6.Saving and Loading
-(IBAction)load:(id)sender{
if (lines!=nil) { [lines release]; } NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; NSData *data = [prefs objectForKey:@"Lineas"]; if (data != nil) { NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data]; if (oldSavedArray != nil) lines = [[NSMutableArray alloc] initWithArray:oldSavedArray]; else lines = [[NSMutableArray alloc] init]; } [self setNeedsDisplay];}
![Page 101: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/101.jpg)
6.Saving and Loading
Line.m
- (void)encodeWithCoder:(NSCoder *)coder;{ [coder encodeFloat:begin.x forKey:@"beginX"]; [coder encodeFloat:begin.y forKey:@"beginY"]; [coder encodeFloat:end.x forKey:@"endX"]; [coder encodeFloat:end.y forKey:@"endY"];}
- (id)initWithCoder:(NSCoder *)coder;{ self = [[Line alloc] init]; if (self != nil) { begin = CGPointMake([coder decodeFloatForKey:@"beginX"],[coder decodeFloatForKey:@"beginY"]); end = CGPointMake([coder decodeFloatForKey:@"endX"],[coder decodeFloatForKey:@"endY"]); } return self;}
![Page 102: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/102.jpg)
7.Circles
- Podemos tocar y arrastrar sobre la pantalla y arrastrar para dibujar una círculo
- Con doble-tap limpiamos la pantalla
![Page 103: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/103.jpg)
//Establecer contextoCGContextRef context = UIGraphicsGetCurrentContext();
//Poner Color[[UIColor blackColor] set];
//Calcular cuadrado que lo englobaCGPoint vector = CGPointMake(circle.end.x-circle.begin.x, circle.end.y-circle.begin.y);float radio = sqrt(pow(vector.x,2) + pow(vector.y,2));float diametro = radio*2;float origenX = circle.begin.x - radio;float origenY = circle.begin.y - radio;CGRect bordes = CGRectMake(origenX,origenY,diametro,diametro);
//Pintar CírculoCGContextFillEllipseInRect(context,bordes);
7.Circles
![Page 104: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/104.jpg)
- UIControl es la superclase de muchos elementos de Cocoa Touch, entre ellos UIButton o UISlider.
- UIControl sobreescribe los mismos métodos de UIResponder que hemos visto en este apartado
- UIControl asocia cada posible evento con una constante. Por ejemplo UIControlEventTouchUpInside.
8.UIControl
![Page 105: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/105.jpg)
8.UIControl
- Veamos como UIControl manejaría el evento UIControlEventTouchUpInside
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {// Referencia al toque que acaba de terminar UITouch *touch = [touches anyObject];
//Posición del punto en el sistema de coordenadas del control CGPoint touchLocation = [touch locationInView:self];
// ¿Esta el punto dentro de los márgenes de mi vista?if (CGRectContainsPoint([self bounds], touchLocation)) {
//Enviar mensaje a todos los targets registrados para este evento[self sendActionsForControlEvents:UIControlEventTouchUpInside];
} else {//Enviar un mensaje diferente[self sendActionsForControlEvents:UIControlEventTouchUpOutside];
}}
![Page 106: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/106.jpg)
20.Core Animation Layer
![Page 107: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/107.jpg)
0.Introduction
- Las animaciones son la marca característica de las interfaces de iOS y Mac OS X
- Cuando queramos usar Core Animation debemos añadir el framework de QuartzCore
- Hay dos clases con las que Core Animation funciona, estas son CALayer y CAAnimation
- CALayer es un buffer que contiene una imagen, se pinta en pantalla mediante hardware, por lo que su funcionamiento es muy rápido.
- CAAnimation causa un cambio mediante interpolación en alguna propiedad de un objeto a lo largo de un periodo de tiempo.
- En este apartado nos centraremos en CALayer
![Page 108: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/108.jpg)
1.Layers and views
- Una UIView es realmente una abstracción de un objeto visible con el que poder interaccionar
- Cada UIView renderiza su contenido en una CALayer que tiene implícitamente
- Un CALayer es un buffer que se pinta directamente sobre la pantalla y que sólo tiene que ver con el renderizado y no con la interacción con el usuario
- No todas las CALayer son implícitas, ya que podemos crear CALayers explícitamente
![Page 109: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/109.jpg)
2.Creating a CALayer
- Imagen de fondo
- Rectángulo rojo que resalta un área
![Page 110: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/110.jpg)
2.Creating a CALayer
- Crear proyecto de tipo Single View Application
- Añadir el framework QuartzCore
- Incluir la librería <QuartzCore/QuartCore.h> donde vayamos a usar este framework
- Añadir imagen a la vista ViewController.xib
- Crear el puntero a la CALayer en ViewController.m
- Instanciar nuestra CALayer en el método ViewDidLoad de ViewController.m
![Page 111: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/111.jpg)
2.Creating a CALayer
ViewController.m
//Crear el nuevo objeto de tipo CALayerboxLayer = [[CALayer alloc] init]; //Ajustar el tamaño adecuado[boxLayer setBounds:CGRectMake(0,0,85,85)]; //Ajustar la posición[boxLayer setPosition:CGPointMake(160,100)]; //Crear un UIColor, después convertirlo a CGColorRef y asociarlo al color de fondoUIColor *rojo = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.5];CGColorRef rojoCG = [rojo CGColor];[boxLayer setBackgroundColor:rojoCG]; //Hacer que la CALayer se sublayer de la layer de la vista del controlador[[self.view layer] addSublayer:boxLayer];
- Instanciaremos la CALayer en el método ViewDidLoad de ViewController.m
![Page 112: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/112.jpg)
3.Layer Content
- Una layer es simplemente una imagen
- Su contenido puede ser generado a partir de una imagen o programáticamente
//Crear imagen, y obtener la CGImageUIImage *layerImage = [UIImage imageNamed:@"image.jpg"];CGImageRef image = [layerImage CGImage]; //Poner la imagen en la layer[boxLayer setContents:(id)image];
- Cada layer tiene una coordenada Z para ver cual se pinta primero
[boxLayer setZPosition:-5];
![Page 113: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/113.jpg)
4.Implicity Animatable Properties
- Las CALayer tienen propiedades que pueden ser modificadas y cuando se cambian realizan una animación hasta alcanzar su nuevo valor
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *t = [touches anyObject];CGPoint p = [t locationInView:self.view]; [boxLayer setPosition:p];
}
- Modifiquemos el ejemplo anterior para que la capa reaccione a nuestros toques en la pantalla con una animación de la CALayer desplazandose hasta la posición donde hemos tocado
![Page 114: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/114.jpg)
5.Programmatically Generating Content
- Para generar el contenido podemos crear un NSObject y cambiar el padre para que herede de CALayer y implementar la rutinas de pintado:
@implementation LayerSubclass
- (void)drawInContext:(CGContextRef)ctx {! UIImage *layerImage = [UIImage imageNamed:@"image.png"];! CGRect boundingBox = CGContextGetClipBoundingBox(ctx);! CGContextDrawImage(ctx, boundingBox, [layerImage CGImage]);}
@end
- Necesario invocar al método setNeedsDisplay de CALayer para que se dibuje su contenido
![Page 115: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/115.jpg)
5.Programmatically Generating Content
- También podemos generar el contenido asignando el delegate de nuestra instancia CALayer a otro objeto que implemente las rutinas de pintado
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{ UIImage *layerImage = [UIImage imageNamed:@"image.jpg"]; CGRect boundingBox = CGContextGetClipBoundingBox(ctx); CGContextDrawImage(ctx,boundingBox,[layerImage CGImage]);}
[boxLayer setDelegate:self];[boxLayer setNeedsDisplay];
- Añadir después de la instanciación
- Necesario invocar al método setNeedsDisplay de CALayer para que se dibuje su contenido
![Page 116: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/116.jpg)
6.Layers, Bitmaps, and Contexts
- Una CALayer es simplemente una imagen que después se vuelca a pantalla.
- Una imagen es una posición de memoria donde se almacena una lista de componentes rojo, verde, azul y alpha para cada pixel
- Cuando ejecutamos instrucciones de QuarzCore estas realizan acciones de pintado sobre una CALayer en concreto, estas instrucciones son ejecutadas en ese contexto
![Page 117: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/117.jpg)
7.Dynamic Layer Content
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{ /* 480 - 1.0 y - cantidadAlpha; */ float cantidadAlpha = p.y/480.0; UIColor *rojo = [UIColor colorWithRed:1 green:0 blue:0 alpha:cantidadAlpha]; CGColorRef rojoCG = [rojo CGColor]; [boxLayer setBackgroundColor:rojoCG];}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *t = [touches anyObject]; p = [t locationInView:self.view]; [boxLayer setPosition:p]; [boxLayer setNeedsDisplay];}
- Modificar el ejemplo para que dependiendo de la posición y de donde toquemos el rectángulo sea más o menos rojo
![Page 118: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/118.jpg)
21.Controlling Animation with CAAnimation
![Page 119: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/119.jpg)
1.Animation Objects
- Un objeto de animación es un conjunto de instrucciones que cambian las propiedades de una instancia de CALayer.
- Muchas de las propiedades de CALayer como opacidad, posición, tamaño, etc pueden ser animadas por los objetos de animación utilizando una función de interpolación.
- Un ejemplo sería “Muevete del punto A al punto B durante 2 segundos”
![Page 120: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/120.jpg)
1.Animation Objects
- En la practica, la forma de utilizar estos objetos de animación es mediante alguna de las subclases que heredan de CAAnimation
![Page 121: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/121.jpg)
2.Spinning with CABasicAnimation
- Imagen de fondo
- 3 botones, cada uno con la imagen de un jugador
- Cuando pulsemos en cada uno de esos botones la pelota se desplazará hacia el jugador
![Page 122: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/122.jpg)
2.Spinning with CABasicAnimation
- Crear proyecto de tipo Single View Application
- Añadir el framework QuartzCore
- Incluir la librería <QuartzCore/QuartCore.h> donde vayamos a usar este framework
- Añadir imágenes y botones a la vista ViewController.xib
- Crear los punteros y hacer los enlaces
- Crear un método para la pulsación de cada botón
![Page 123: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/123.jpg)
2.Spinning with CABasicAnimation
- Método de uno de los botones
-(IBAction)jugador1:(id)sender{ CABasicAnimation *animacion = [CABasicAnimation animationWithKeyPath:@"position"]; [animacion setDuration:1.0];
CGPoint p1 = CGPointMake(pelota.center.x, pelota.center.y); CGPoint p2 = CGPointMake(jugador1.center.x, jugador1.center.y);
[animacion setFromValue:[NSValue valueWithCGPoint:p1]]; [animacion setToValue:[NSValue valueWithCGPoint:p2]]; [[pelota layer] addAnimation:animacion forKey:@"animacion"];}
![Page 124: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/124.jpg)
3.Timing functions
- En nuestro ejemplo la animación comienza de repente porque se hace una interpolación lineal
- Podemos cambiar la función de interpolación por otra diferente como por ejemplo una que comience aceleradamente y termine desacelerando
CAMediaTimingFunction *tf = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[animacion setTimingFunction:tf];
Diferentes valores de interpolación son:
kCAMediaTimingFunctionLinearkCAMediaTimingFunctionEaseInEaseOutkCAMediaTimingFunctionEaseInkCAMediaTimingFunctionEaseOut
![Page 125: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/125.jpg)
4.Animation completion
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { [pelota setCenter:puntoFinal];}
- Asociar nuestro controlador como delegate de la animación
- Cuando la animación termine se realizará una llamada al método animationDidStop que deberemos sobreescribir para realizar una acción justo después de que la animación haya terminado.
[animacion setDelegate:self];
![Page 126: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/126.jpg)
5.Bouncing with a CAKeyframeAnimation
- En las animaciones con CAKeyframeAnimation especificaremos diferentes valores a lo largo del tiempo. Cada valor será un key frame
- Vamos a extender el ejemplo anterior para que la pelota cambie de tamaño a lo largo del tiempo, simulando de esta forma como si subiera en altura
![Page 127: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/127.jpg)
5.Bouncing with a CAKeyframeAnimation
//Crear la animación de tipo key frames CAKeyframeAnimation *animacion3 = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; //Crear los valores por los que pasará el parámetro transform CATransform3D t1 = CATransform3DMakeScale(1.0,1.0,1.0); CATransform3D t2 = CATransform3DMakeScale(2.0,2.0,1.0); CATransform3D t3 = CATransform3DMakeScale(1.0,1.0,1.0); //Asociamos los diferentes valores [animacion3 setValues:[NSArray arrayWithObjects: [NSValue valueWithCATransform3D:t1], [NSValue valueWithCATransform3D:t2], [NSValue valueWithCATransform3D:t3], nil]]; //Ajustamos el tiempo que durará la animación y configuramos su delegado [animacion3 setDuration:2.0]; [animacion3 setDelegate:self]; //Añadimos la animación [[pelota layer] addAnimation:animacion3 forKey:@"keyAnimation"];
![Page 128: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/128.jpg)
6.More Animation
- Como hemos visto se pueden solapar varias animaciones en un mismo instante de tiempo
- Extender el ejemplo anterior para que la pelota:- tarde 2 segundos en desplazarse de un jugador a otro- mientras tanto su alpha cambia de 0.0 a 1.0 durante 1 segundo- además su escala cambia a lo largo de 2 segundos los valores 1,2,1- que los pelotazos empiecen con velocidad y terminen en seco
![Page 129: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/129.jpg)
7.The Presentation Layer and the Model Layer
- Cuando una instancia de la clase CALayer esta siendo animada esta tiene unos parámetros como son opacity, transform, position que cambian de valor. Cuando hay una animación en marcha, ldicha clase tiene dos copias de esos parámetros.
- La capa de modelo contiene los valores finales de la animación
- La capa de presentación contiene los valores interpolados para ese instante de tiempo.
- Esto es útil por ejemplo cuando se tienen objetos con una animación en curso y el usuario realiza un toque sobre ellos. En ese caso la información correcta de la posición la tendrá la capa de presentación.
CGPoint whereIsItWhenAnimationStops = [layer position];CGPoint whereIsItNow = [[layer presentationLayer] position];
![Page 130: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/130.jpg)
22.Blocks and Categories
![Page 131: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/131.jpg)
1.Colorizing TouchDrawView
- Partiremos de nuestro ejemplo TouchDrawView
- Vamos a utilizar bloques para pintar con diferentes colores
![Page 132: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/132.jpg)
1.Colorizing TouchDrawView
- Antes de nada vamos a modificar la clase “line” para que almacene un color
Line.h :
#import <Foundation/Foundation.h>
@interface Line : NSObject { CGPoint begin; CGPoint end; UIColor *color;}
@property(nonatomic) CGPoint begin;@property(nonatomic) CGPoint end;@property(nonatomic,retain) UIColor *color;
@end
![Page 133: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/133.jpg)
1.Colorizing TouchDrawViewLine.m :
#import "Line.h"
@implementation Line
@synthesize begin,end;@synthesize color;
- (void)encodeWithCoder:(NSCoder *)coder;{ [coder encodeFloat:begin.x forKey:@"beginX"]; [coder encodeFloat:begin.y forKey:@"beginY"]; [coder encodeFloat:end.x forKey:@"endX"]; [coder encodeFloat:end.y forKey:@"endY"];}
- (id)initWithCoder:(NSCoder *)coder;{ self = [[Line alloc] init]; if (self != nil) { color = [UIColor blackColor]; begin = CGPointMake([coder decodeFloatForKey:@"beginX"],[coder decodeFloatForKey:@"beginY"]); end = CGPointMake([coder decodeFloatForKey:@"endX"],[coder decodeFloatForKey:@"endY"]); } return self;}
-(void)dealloc{ [color release];}
@end
![Page 134: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/134.jpg)
1.Colorizing TouchDrawView
- En TouchDrawView.m, en el método drawRect sustituiremos:
[[UIColor blackColor] set];
- Por la propiedad el color de nuestra linea, quedando el bucle de la siguiente forma:
for (Line *line in lines) { [[line color] set]; CGContextMoveToPoint(context, [line begin].x, [line begin].y); CGContextAddLineToPoint(context, [line end].x, [line end].y); CGContextStrokePath(context); }
![Page 135: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/135.jpg)
2.Blocks
- Trozos de código que se pueden guardar en variables o pasar como argumentos
- También se pueden devolver como el resultado de un mensaje y ejecutar posteriormente
- Los bloques capturan el entorno léxico, entenderemos que quiere decir esto unas transparencias más adelante.
![Page 136: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/136.jpg)
3.Blocks as variables
-(void)transformLineColorsWithBlock:(UIColor* (^)(Line*))color{ for (Line *l in lines) { UIColor *c = color(l); [l setColor:c]; } [self setNeedsDisplay];}
- Vamos a crear un método que reciba como variable un bloque.
- El nombre de esa variable la llamamos color
- Dentro del método usamos el bloque color si fuera una función
![Page 137: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/137.jpg)
3.Blocks as variables
- Después crearemos un botón en la interface y lo enlazaremos con un método que llamaremos colorear
-(IBAction)colorear:(id)sender{
UIColor *(^esquemaDeColor)(Line*)=^(Line *l) { float longitudX = l.end.x - l.begin.x; float longitudY = l.end.y - l.begin.y; /* Regla de tres 320 - 1.0 longitudX - r
480 - 1.0 longitudY - g */ float r=longitudX/320.0; float g=longitudY/480.0; float b=1.0; return [UIColor colorWithRed:r green:g blue:b alpha:1]; }; [self transformLineColorsWithBlock:esquemaDeColor];}
![Page 138: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/138.jpg)
4.Capturing variables
- Los bloques capturan el entorno léxico
-(void)metodo{ int value = 5; void (^aBlock)() = ^(void){ NSLog(@"valor=%d",value); }; aBlock(); //Imprime "valor=5" value = 10; aBlock(); //Imprime "valor=5"}
![Page 139: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/139.jpg)
5.Using blocks with other build-in methods
- Podemos usar bloques en las siguientes acciones:
- Ordenación (el bloque se proporciona como método de comparación)- Notificación (cuando ocurra un evento ejecuta el bloque)- Gestores de error (cuando ocurra un error ejecutar bloque)- Gestores de finalización (cuando termines de hacer una tarea, ejecutar bloque)- Animación de vistas- Para multitarea mediante Grand Dispatch Central
![Page 140: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/140.jpg)
6.Keeping code compact with blocks
- Vamos a ver un ejemplo de uso de bloques en una notificación
- En nuestro ejemplo vamos a hacer que cuando el dispositivo rote todas las lineas se pongan rojas
- Añadimos la siguiente notificación al método initWithCoder de TouchDrawView.m
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceOrientationDidChangeNotification object:nil queue:nil usingBlock: ^(NSNotification *note) { [self transformLineColorsWithBlock: ^(Line *l) { return [UIColor redColor]; }]; }];
![Page 141: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/141.jpg)
7.Categories
- Crear una categoría consiste en coger una clase existente y añadirle métodos que después podrán ser utilizables sin tener que hacer subclassing
- En nuestro ejemplo crearemos una clase de tipo NSObject y la llamaremos “UIColor+Inverse”
UIColor+Inverse.h :
#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>
@interface UIColor (Inverse)
-(UIColor*)colorInvertido;
@end
![Page 142: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/142.jpg)
7.Categories
UIColor+Inverse.m :
#import "UIColor+Inverse.h"
@implementation UIColor (Inverse)
-(UIColor*)colorInvertido{ CGColorRef cgCLR = [self CGColor]; const CGFloat *components = CGColorGetComponents(cgCLR); float r = 1.0 - components[0]; float g = 1.0 - components[1]; float b = 1.0 - components[2]; UIColor *colorInvertido = [UIColor colorWithRed:r green:g blue:b alpha:1.0]; return colorInvertido;}
@end
![Page 143: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/143.jpg)
7.Categories
- Para usarlo en nuestro ejemplo, en TouchDrawView.m importaremos la cabecera UIColor+Inverse.h
- Ya podemos usar el método colorInvertido con cualquier instancia de UIColor
- Modifiquemos el ejemplo anterior, para que el método transformLineColorsWithBlock invierta el color devuelto por el bloque colorear antes de asignarlo al color de la linea
-(void)transformLineColorsWithBlock:(UIColor* (^)(Line*))color{ for (Line *l in lines) { UIColor *c = color(l); [l setColor:[c colorInvertido]]; } [self setNeedsDisplay];}
![Page 144: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/144.jpg)
8.Memory Managment and Blocks
- Los bloques en Cocoa son objetos aunque algo limitados. Se pueden enviar los siguientes mensajes a los bloques:
- copy- retain- release- autorelease
Por defecto los bloques reservan memoria automáticamente cuando se crean y son destruidos cuando la función que los crea se completa.
![Page 145: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/145.jpg)
9.Pros and Cons of Callback Options
- Contras:
- Sintaxis compleja- Difíciles de usar
- Pros:
- Código más compacto- Necesario conocerlos métodos predefinidos en su uso con Grand Dispatch Central (GCD) o para pasar como criterio de comparación en una ordenación por ejemplo.- Útiles en algunas circunstancias especiales. Por ejemplo como los bloques retienen en memoria los objetos que usan durante su ejecución, si un bloque se pasa como fragmento de código a usar al terminar una determinada acción nos garantizamos de que todos los objetos que van a ser usados permanecen en memoria hasta que se complete esta acción.
![Page 146: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/146.jpg)
23.Web Services and UIWebView
![Page 147: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/147.jpg)
1.Web Services- Cualquier navegador de internet utiliza el protocolo HTTP para comunicarse con un servicio web.
- La interacción más simple consiste en que el cliente envía una petición sobre una URL específica al servidor y este le responde enviando el contenido de la página que se ha solicitado.
- Para interacciones más complejas el navegador puede incluir parámetros en su petición. Estos parámetros son procesados por el servidor para enviar el contenido de una página dinámicamente construida con respecto a esos parámetros.
- Usar un servicio web desde una aplicación iOS requiere los siguientes pasos:
- Formatear los datos para enviar como XML o JSON- Enviar los datos en una petición HTTP- Recibir la respuesta HTTP- Parsear y procesar el los datos recibidos como XML o JSON
![Page 148: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/148.jpg)
2.Starting the Nerdfeed application
- Lector RSS
- Una lista con noticias RSS obtenidas de un servidor.
- Tocando sobre cada una de esos elementos podremos ver la noticia
![Page 149: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/149.jpg)
2.Starting the Nerdfeed application
- Crear proyecto de tipo Empty Application
- Añadir una nueva clase de tipo NSObject y cambiar su padre para que herede de UITableViewController
- Añadir a este fichero métodos requeridos de data source
- En AppDelegate.m crear una instancia de ListViewController y asignarla como root view controller de un navigation controller.
- Hacer el navigation controller el root view controller de window
![Page 150: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/150.jpg)
2.Starting the Nerdfeed application
- En AppDeletage.m en el método didFinishLaunchingWithOptions añadiremos
//Instanciar controllador ListViewControllerListViewController *lvc =
[[ListViewController alloc] initWithStyle:UITableViewStylePlain];[lvc autorelease]; //Instanciar controlador de navegación UINavigationController *masterNav =
[[UINavigationController alloc] initWithRootViewController:lvc];[masterNav autorelease]; //Asignar como rootViewController el control de navegación[[self window] setRootViewController:masterNav];
- Con eso tendremos nuestro UITableView en pantalla, pero está vacío
![Page 151: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/151.jpg)
3.Fetching data from a URL
- 1. Crear contenedor de datos
- 2. Iniciar conexión
- 3. Recoger datos con los métodos delegados
- Para crear nuestro contenedor de datos:
ListViewController.h
NSMutableData *responseData;
ListViewController.m : Instanciarlo Antes de usarlo
responseData = [[NSMutableData data] retain];
![Page 152: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/152.jpg)
4.Working with NSURLConnection
- Iniciaremos la conexión
responseData = [[NSMutableData data] retain];
NSURL *baseURL = [[NSURL URLWithString:@"http://www.atomicflavor.com/feed/"] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:baseURL];[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
- Después debemos implementar una serie de métodos en nuestro controlador para que se vayan recibiendo los datos
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error- (void)connectionDidFinishLoading:(NSURLConnection *)connection
- Asignamos nuestro controlador como delegate de la conexión
![Page 153: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/153.jpg)
4.Working with NSURLConnection
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ [responseData setLength:0];}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [responseData appendData:data];}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ NSLog(@"No se pudo descargar el XML");}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{! //Realizar parseo}
- Métodos a implementar
![Page 154: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/154.jpg)
5.Parsing XML
- Veamos un fragmento de lo que contiene un fichero XML y lo que vamos a parsear
<item><title>Entrevista a Atomic Flavor en Baquia TV</title><link>http://www.atomicflavor.com/entrevista-a-atomic-flavor-en-baquia-tv/</link><comments>http://www.atomicflavor.com/entrevista-a-atomic-flavor-en-baquia-tv/#comments</comments><pubDate>Wed, 15 Jun 2011 09:28:48 +0000</pubDate>
- Vamos a usar NSXMLParser, que es la librería incluida por defecto en el SDK de iOS
![Page 155: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/155.jpg)
5.Parsing XML
- 1. Implementar el protocolo NSXMLParserDelegate
- 2. Declarar cadenas del XML
- 3. Sobreescribir los métodos de parseo
- 4. Invocar comienzo de parseo
![Page 156: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/156.jpg)
5.Parsing XML
- 1. Declarar cadenas de parseo
NSXMLParser * rssParser;
NSMutableData *responseData;NSMutableArray *items;!NSMutableDictionary * item;!NSString * currentElement;
NSMutableString * currentTitle;NSMutableString * currentDate;NSMutableString * currentSummary;NSMutableString * currentLink;
![Page 157: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/157.jpg)
5.Parsing XML
- 2. Iniciar parseo
! NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
! NSData *data= [str dataUsingEncoding:NSUTF8StringEncoding];
items = [[NSMutableArray alloc] init];!! rssParser = [[[NSXMLParser alloc] initWithData:data] autorelease];! [rssParser setDelegate:self];! [rssParser setShouldProcessNamespaces:NO];! [rssParser setShouldReportNamespacePrefixes:NO];! [rssParser setShouldResolveExternalEntities:NO];! [rssParser parse];!
![Page 158: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/158.jpg)
5.Parsing XML
- 3. Sobreescribir métodos del delegado NSXMLParserDelegate:
- 3.1 Empieza parseo de elemento
- 3.2 Encontrada cadena
- 3.4 Termina parseo de elemento
- 3.5 Terminado de parsear
![Page 159: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/159.jpg)
5.Parsing XML
- 3.1 Empieza parseo de elemento
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{! currentElement = [elementName copy];!! if ([elementName isEqualToString:@"item"]) ! {! ! item = [[NSMutableDictionary alloc] init];! ! currentTitle = [[NSMutableString alloc] init];! ! currentDate = [[NSMutableString alloc] init];! ! currentSummary = [[NSMutableString alloc] init];! ! currentLink = [[NSMutableString alloc] init];! }}
![Page 160: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/160.jpg)
5.Parsing XML
- 3.2 Encontrada cadena
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{! if ([currentElement isEqualToString:@"title"]) {! ! [currentTitle appendString:string];! } else if ([currentElement isEqualToString:@"link"]) {! ! [currentLink appendString:string];! } else if ([currentElement isEqualToString:@"pubDate"]) {! ! [currentDate appendString:string];! }}
![Page 161: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/161.jpg)
5.Parsing XML
- 3.4 Termina parseo de elemento
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{! if ([elementName isEqualToString:@"item"]) {! ! [item setObject:currentTitle forKey:@"title"];! ! [item setObject:currentLink forKey:@"link"];! ! [item setObject:currentDate forKey:@"pubDate"];! ! [items addObject:[item copy]];! }}
![Page 162: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/162.jpg)
5.Parsing XML
- 3.5 Terminado de parsear
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {! NSLog(@"No se pudo parsear el XML");}
- (void)parserDidEndDocument:(NSXMLParser *)parser {! [[self tableView] reloadData];}
![Page 163: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/163.jpg)
5.Parsing XML
- Por último modificamos los métodos de nuestro ListViewController para que muestren la lista de elementos recuperados
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return [items count];}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"] autorelease]; } NSMutableDictionary *i = [items objectAtIndex:indexPath.row]; [[cell textLabel] setText:[i objectForKey:@"title"]]; return cell;}
![Page 164: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/164.jpg)
5.Parsing XML
- También crearemos un método para que podamos invocar el comienzo del parseo desde AppDelegate
-(void)comenzarConexion{ responseData = [[NSMutableData data] retain]; NSURL *baseURL = [[NSURL URLWithString:@"http://www.atomicflavor.com/feed/"] retain]; NSURLRequest *request = [NSURLRequest requestWithURL:baseURL]; [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];}
![Page 165: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/165.jpg)
6.A quick tip on logging
- En este ejercicio veremos como se imprime mucha información en la consola de depuración sobre todo el contenido que recibimos y enviamos
- Lo que vamos a hacer es crear diferentes etiquetas para NSLog en nuestro fichero Nerdfeed_Prefix.pch que es donde importamos las librerías del precompilador
#define WSLog NSLog #define OSLog NSLog
- Cada vez que queramos imprimir información relaccionada con los webservices usaremos WSLog en lugar de NSLog. Para el resto de información usaremos OSLog.
- Después cuando queramos que la información de los webservices no se imprima deberemos redefinir la etiqueta en nuestra clase:
#define WSLog
![Page 166: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/166.jpg)
7.UIWebView
- UIViewController.h :
#import <Foundation/Foundation.h>
@interface WebViewController : UIViewController { }
@property (nonatomic,readonly) UIWebView *webView;
@end
- Creamos una nueva clase de tipo NSObject y le cambiamos el padre para que herede de UIViewController
![Page 167: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/167.jpg)
7.UIWebView
#import "WebViewController.h"
@implementation WebViewController
@synthesize webView;
- (void) loadView{ CGRect screenFrame = [[UIScreen mainScreen] applicationFrame]; UIWebView *wv = [[UIWebView alloc] initWithFrame:screenFrame]; [wv setScalesPageToFit:YES]; [self setView:wv]; [wv release];}
-(UIWebView*)webView { return (UIWebView*)[self view];}
@end
- UIViewController.m :
![Page 168: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/168.jpg)
7.UIWebView
- Instanciarlo desde el AppDelegate
- Crear una propiedad en ListViewController para apuntar a WebViewController
WebViewController *webViewController;
@property(nonatomic,retain) WebViewController *webViewController;
@synthesize webViewController;
![Page 169: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/169.jpg)
7.UIWebView
- Método para cuando seleccionemos alguna fila de ListViewController
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ //Desplazar la vista actual a webViewController [[self navigationController] pushViewController:webViewController animated:YES];
//Obtener el elemento NSMutableDictionary *i = [items objectAtIndex:indexPath.row]; //Limpiar cadena de parásitos finales NSString *cadenaURL = [i objectForKey:@"link"]; WSLog(@"[cadena =%@]",cadenaURL); cadenaURL = [cadenaURL substringToIndex:[cadenaURL length]-1];! cadenaURL = [cadenaURL stringByReplacingOccurrencesOfString:@" " withString:@""];! cadenaURL = [cadenaURL stringByReplacingOccurrencesOfString:@"\n" withString:@""]; WSLog(@"[cadena =%@]",cadenaURL); //Crear NSURL NSURL *url = [NSURL URLWithString:cadenaURL]; //Crear petición con esa URL NSURLRequest *req = [NSURLRequest requestWithURL:url]; //Decirle a webviewcontroller que cargue esa petición [[webViewController webView] loadRequest:req]; //Poner como título del control de navegación el título de la noticia [[webViewController navigationItem] setTitle:[i objectForKey:@"title"]];}
![Page 170: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/170.jpg)
8.NSXMLParser
- En este ejercicio hemos utilizado NSXMLParser que es el parseador disponible por defecto en la api del SDK de iOS.
- En internet podremos encontrar otras librerías de terceros que también podremos usar para parsear fichero XML sustituyendo a NSXMLParser
- Algunas de las librerías de terceros que podremos encontrar disponibles son:
- libxml2- TBXML- TouchXML- KissXML- TinyXML- GDataXML
![Page 171: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/171.jpg)
9.The Request Body
- Veamos como es en detalle cada una de las peticiones que realiza nuestro programa.
- Hay tres partes, la linea de petición, las cabeceras HTTP y el cuerpo HTTP
![Page 172: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/172.jpg)
10.Credentials
- Cuando se accede a un servicio web, hay veces que es necesario identificarse para poder trabajar con dicho servicio.
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// Se ha fallado 2 veces if ([challenge previousFailureCount] > 1) {
//Dar mensaje de aviso } else { // Responder NSURLCredential *cred = [[[NSURLCredential alloc]
initWithUser:@"user" password:@"pass"
persistence:NSURLCredentialPersistenceForSession] autorelease]; [[challenge sender] useCredential:cred forAuthenticationChallenge:challenge]; }}
![Page 173: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/173.jpg)
11.More Data
- Vamos a crear una clase CustomCell que sea subclase de UTTableViewCell que tenga varios labels, uno para el título y otro para la fecha.
CustomCell.h:
#import <UIKit/UIKit.h>
@interface CustomCell : UITableViewCell { UILabel *titulo; UILabel *hora;}
@property(nonatomic,retain) UILabel *titulo;@property(nonatomic,retain) UILabel *hora;
@end
![Page 174: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/174.jpg)
11.More Data
- Método constructor
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { //Instanciamos los labels titulo = [[UILabel alloc] initWithFrame:CGRectZero]; hora = [[UILabel alloc] initWithFrame:CGRectZero]; [titulo setBackgroundColor:[UIColor clearColor]]; [hora setBackgroundColor:[UIColor clearColor]];
//Los añadimos a el contenido de la vista [[self contentView] addSubview:titulo]; [[self contentView] addSubview:hora]; //Liberamos [titulo release]; [hora release]; } return self;}
![Page 175: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/175.jpg)
11.More Data
- Colocación de SubVistas
-(void)layoutSubviews{ [super layoutSubviews]; CGRect bounds = [[self contentView] bounds];
float inset = 5.0; float w = bounds.size.width; float h = bounds.size.height; CGRect titleFrame = CGRectMake(inset,inset, w, (h/2)); CGRect hourFrame = CGRectMake(inset,inset+h/2, w, (h/2)); [titulo setFrame:titleFrame]; [hora setFrame:hourFrame];}
![Page 176: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/176.jpg)
11.More Data
- Modificar cellForRowAtIndexPath de ListViewController.m
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:@"CustomCell"];
if (cell == nil) { cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CustomCell"] autorelease]; } NSMutableDictionary *i = [items objectAtIndex:indexPath.row]; [[cell titulo] setText:[i objectForKey:@"title"]]; [[cell hora] setText:[i objectForKey:@"pubDate"]]; return cell;}
![Page 177: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/177.jpg)
12.More UIWebView
- Añadir UIActivityIndicatorView a nuestra clase WebViewController en el centro de la pantalla
- Hay que implementar UIWebViewDelegate en nuestro controlador
- Vamos a sobreescribir los métodos de UIWebViewDelegate:
- Cuando la noticia empiece a cargar en el centro de la pantalla deberemos ver un UIActivityIndicatorView con su animación activada
- Cuando la noticia se haya terminado la carga, el UIActivityIndicatorView desaparecerá
![Page 178: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/178.jpg)
12.More UIWebView
- Cambios sobre loadView
- (void) loadView{ CGRect screenFrame = [[UIScreen mainScreen] applicationFrame]; UIWebView *wv = [[UIWebView alloc] initWithFrame:screenFrame]; [wv setScalesPageToFit:YES]; [wv setDelegate:self]; activityIndicator = [[UIActivityIndicatorView alloc] init]; [activityIndicator setHidesWhenStopped:TRUE]; [activityIndicator stopAnimating]; [activityIndicator setBackgroundColor:[UIColor clearColor]]; [activityIndicator setColor:[UIColor blackColor]]; [self setView:wv];
[self.view addSubview:activityIndicator]; [activityIndicator setCenter:CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2)];
[activityIndicator release]; [wv release];}
![Page 179: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/179.jpg)
12.More UIWebView
- Métodos de UIWebViewDelegate:
- (void)webViewDidStartLoad:(UIWebView *)webView{! [activityIndicator startAnimating];}
- (void)webViewDidFinishLoad:(UIWebView *)webView{ [activityIndicator stopAnimating]; }
![Page 180: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/180.jpg)
24.UISplitViewController
![Page 181: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/181.jpg)
1.Splitting Up Nerdfeed
- Tanto iPhone como iPod Touch tienen un tamaño de pantalla bastante limitado, por eso la manera usual de presentar las vistas es mediante un UINavigationController.
- En cambio, el iPad tiene una pantalla mucho mayor y puede utilizar clases predefinidas como UISplitViewController que sólo están disponible para iPad.
- Para trabajar con UISplitViewController debemos tener dos controladores, el master y el detail.
- El controlador master ocupará poco en la pantalla y será una lista que nos permita elegir que contenido visualizar
- El controlador detail ocupará la mayor parte de la pantalla y mostrará en detalle el contenido seleccionado en el master
![Page 182: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/182.jpg)
1.Splitting Up Nerdfeed
- Añadiremos un UISplitViewController a nuestro ejemplo Nerdfeed
![Page 183: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/183.jpg)
1.Splitting Up Nerdfeed
- Partimos de el proyecto anterior
- Realizamos cambios en AppDelegate para instanciar el UISplitViewController en caso de estar ejecutando el programa en un iPad
- Configuramos los controladores para que soporten cambios a orientación horizontal si el programa se esta ejecutando en un iPad
![Page 184: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/184.jpg)
1.Splitting Up Nerdfeed
- Modificamos el método didFinishLaunchingWithOptions del fichero AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; //Instanciar controllador ListViewController ListViewController *lvc = [[ListViewController alloc] initWithStyle:UITableViewStylePlain]; [lvc autorelease]; //Instanciar controlador de navegacion UINavigationController *masterNav = [[UINavigationController alloc] initWithRootViewController:lvc]; [masterNav autorelease]; WebViewController *wvc = [[[WebViewController alloc] init] autorelease]; [lvc setWebViewController:wvc];
...
![Page 185: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/185.jpg)
1.Splitting Up Nerdfeed
.... if ([[UIDevice currentDevice] userInterfaceIdiom] ==UIUserInterfaceIdiomPad){ //El detalle debe ir en un navigation controller UINavigationController *detailNav = [[UINavigationController alloc] initWithRootViewController:wvc]; [detailNav autorelease]; NSArray *vcs = [NSArray arrayWithObjects:masterNav,detailNav, nil]; UISplitViewController *svc = [[[UISplitViewController alloc] init] autorelease]; [svc setDelegate:wvc]; [svc setViewControllers:vcs]; [[self window] setRootViewController:svc]; } else { //Asignar como rootViewController el control de navegación [[self window] setRootViewController:masterNav]; } [lvc comenzarConexion]; [self.window makeKeyAndVisible]; return YES;}
![Page 186: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/186.jpg)
1.Splitting Up Nerdfeed
- Añadir el método shouldAutorotateToInterfaceOrientation a ListViewController.m y WebViewController.m para que la app soporte orientación horizontal
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ if ([[UIDevice currentDevice] userInterfaceIdiom] ==UIUserInterfaceIdiomPad){ return YES; } else { return interfaceOrientation == UIInterfaceOrientationPortrait; }}
- Solo se realizará el cambio a horizontal en iPad
![Page 187: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/187.jpg)
2.Master-Detail Communication
- Como desde ListViewController tenemos un puntero hacia WebViewController, podremos seguir indicando a este controlador la página que debe cargar
- Por lo general en el master siempre tendremos un puntero hacia el detalle para modificar el contenido
- En el caso de estar disponible un splitViewController tendremos quemodificar la forma de presentar el contenido cuando se seleccione un elemento de la lista. Para ello realizaremos el siguiente cambio en didSelectRowAtIndexPath:
if (![self splitViewController]) {[[self navigationController] pushViewController:webViewController animated:YES];
}
![Page 188: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/188.jpg)
3.Displaying the Master View Controller in Portrait Mode
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc{ [barButtonItem setTitle:@"Lista"]; self.navigationItem.leftBarButtonItem = barButtonItem;}
- (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem{ self.navigationItem.leftBarButtonItem = nil;}
- Hacemos que nuestro WebViewController implemente UISplitViewControllerDelegate y sobreescribimos los siguientes métodos
![Page 189: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/189.jpg)
4.Universalizing Nerdfeed
- Ahora podemos probar con los diferentes simuladores de iPhone o iPad para ver como la aplicación se comporta de forma diferente.
![Page 190: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/190.jpg)
25.Media Playback and Background Execution
![Page 191: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/191.jpg)
1.Creating the MediaPlayer Application
- Muchas aplicaciones necesitan reproducir audio o video
- En este tema aprenderemos a utilizar la forma mas común de reproducir contenido de vídeo y audio utilizando las rutinas que nos ofrece la SDK de iOS
- También aprenderemos más sobre multitarea y ejecución en segundo plano
![Page 192: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/192.jpg)
1.Creating the MediaPlayer Application
- Aplicación multimedia
- Reproducir fichero de audio
- Reproducir un sonido del sistema corto
- Reproducir fichero de video
![Page 193: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/193.jpg)
1.Creating the MediaPlayer Application
- Crear proyecto de tipo Single View Application
- Creamos 3 botones en ViewController.xib y sus correspondientes métodos que enlazaremos a estos botones
- Programamos el método para cada uno de los botones
![Page 194: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/194.jpg)
2.System Sounds
- Los llamados sonidos del sistema son sonidos cortos sin comprimir que se utilizan típicamente en las interfaces o cuando el usuario realiza alguna acción
- El framework Auditoolbox nos permite registrar una serie de sonidos en el servidor de sonidos del sistema. Estos sonidos deben ser :
- Menores a 30 segundos de duración- Estar empaquetados en formato PCM o IMA4- Ser de uno de los siguientes tipos: CAF, WAV o AIFF
afconvert -f caff -d LEI16@44100 -c 1 sound.mp3 sound.caf
- Como pasar de mp3 a caf :
![Page 195: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/195.jpg)
2.System Sounds
- Importar framework de AudioToolbox
- Añadir objeto de tipo SystemSoundID
ViewController.h :
#import <UIKit/UIKit.h>#import <AudioToolbox/AudioToolbox.h>
@interface ViewController : UIViewController { SystemSoundID sonidoCorto;}
-(IBAction)reproducirAudio:(id)sender;-(IBAction)reproducirSonidoCortoSistema:(id)sender;-(IBAction)reproducirVideo:(id)sender;
@end
![Page 196: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/196.jpg)
3.Registering system sounds
//Puntero a su ruta NSString *soundPath = [[NSBundle mainBundle] pathForResource:@"sound" ofType:@"caf"]; if (soundPath) { //Creamos un NSURL y lo cargamos en sonidoCorto NSURL *soundURL = [NSURL fileURLWithPath:soundPath]; AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &sonidoCorto); }
- Cargamos el sonido en viewDidLoad de ViewController.m
![Page 197: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/197.jpg)
4.Playing system sounds
- Para reproducir el sonido
-(IBAction)reproducirSonidoCortoSistema:(id)sender{ AudioServicesPlaySystemSound(sonidoCorto);}
- Para reproducir el sonido y que vibre el dispositivo
-(IBAction)reproducirSonidoCortoSistema:(id)sender{ AudioServicesPlaySystemSound(sonidoCorto); AudioServicesPlayAlertSound(sonidoCorto);}
- Descargar sonido
AudioServicesDisposeSystemSoundID(sonidoCorto);
![Page 198: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/198.jpg)
5.Compressed Audio Files
- Para reproducir sonidos comprimidos de más de 30 segundos usaremos AVAudioPlayer
- Primero importamos el framework AVFoundation y creamos un puntero de tipo AVAudioPlayer
#import <UIKit/UIKit.h>#import <AudioToolbox/AudioToolbox.h>#import <AVFoundation/AVFoundation.h>
@interface ViewController : UIViewController { SystemSoundID sonidoCorto; AVAudioPlayer *musica;}
-(IBAction)reproducirAudio:(id)sender;-(IBAction)reproducirSonidoCortoSistema:(id)sender;-(IBAction)reproducirVideo:(id)sender;
@end
![Page 199: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/199.jpg)
5.Compressed Audio Files
- Cargamos la canción en viewDidLoad de ViewController.m
NSString *musicPath = [[NSBundle mainBundle] pathForResource:@"music" ofType:@"mp3"]; if (musicPath) { //Creamos un NSURL y lo cargamos en musica NSURL *musicURL = [NSURL fileURLWithPath:musicPath]; musica = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil]; [musica setDelegate:self]; }
- Implementamos en ViewController el delegado AVAudioPlayerDelegate para poder capturar eventos
![Page 200: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/200.jpg)
5.Compressed Audio Files
- Reproducimos la canción
-(IBAction)reproducirAudio:(id)sender{ if ([musica isPlaying]) { [musica stop]; [sender setTitle:@"Reproducir música" forState:UIControlStateNormal]; } else { [musica play]; [sender setTitle:@"Parar música" forState:UIControlStateNormal]; }}
![Page 201: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/201.jpg)
5.Compressed Audio Files
- Si queremos hacer cosas más avanzadas con AVAudioPlayer sobreescribimos los métodos de su delegado
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player{ [musica play];}
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{ NSLog(@"Reproducción terminada");}
![Page 202: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/202.jpg)
6.Playing Movie Files
- MPMovieplayerController es el responsable de reproducir vídeos en iOS.
- La aplicación de YouTube y de Vídeos utilizan esta misma clase para reproducir vídeos
- Solo reproduce vídeos en dos formatos:
- H264 (Baseline Profile Level 3.0)- MPEG-4 Part2 video (Simple Profile)
- Para codificar cualquier video en estos formatos podemos utilizar iTunes. Seleccionando un vídeo y desde el menú avanzado.
- También podemos utilizar programas de terceros que nos permitan realizar este tipo de conversiones
![Page 203: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/203.jpg)
6.Playing Movie Files
- Importar framework de MediaPlayer
- Añadir objeto de tipo MPMoviePlayerController
ViewController.h :
#import <UIKit/UIKit.h>#import <AudioToolbox/AudioToolbox.h>#import <AVFoundation/AVFoundation.h>#import <MediaPlayer/MediaPlayer.h>
@interface ViewController : UIViewController<AVAudioPlayerDelegate> { SystemSoundID sonidoCorto; AVAudioPlayer *musica; MPMoviePlayerController *video;}
-(IBAction)reproducirAudio:(id)sender;-(IBAction)reproducirSonidoCortoSistema:(id)sender;-(IBAction)reproducirVideo:(id)sender;
@end
![Page 204: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/204.jpg)
6.Playing Movie Files
- Cargamos el video en viewDidLoad de ViewController.m
NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"video" ofType:@"m4v"]; if (moviePath) { //Creamos un NSURL y lo cargamos en musica NSURL *movieURL = [NSURL fileURLWithPath:moviePath]; video = [[MPMoviePlayerController alloc] initWithContentURL:movieURL]; [self.view addSubview:video.view]; float h = self.view.bounds.size.height/2; float w = self.view.bounds.size.width;
[video.view setFrame:CGRectMake(0, h, w, h)]; }
-(IBAction)reproducirVideo:(id)sender{ [video play];}
- Y lo reproducimos
![Page 205: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/205.jpg)
7.MPMoviePlayerViewController
- Si queremos presentar un vídeo en pantalla completa usaremos la clase MPMoviePlayerViewController y después lanzaremos su presentación
MPMoviePlayerViewController *playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:movieURL];
[self presentMoviePlayerViewControllerAnimated:playerViewController];
![Page 206: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/206.jpg)
8.Preloading video
- Cuando iniciamos la carga de un vídeo no está disponible de manera inmediata. Mas aún si lo cargamos en streaming desde un servidor
- Podemos añadir a nuestro objeto de vídeo una notificación apuntando a un método para que sea llamado cuando el vídeo se haya terminado de cargar completamente.
NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"video" ofType:@"m4v"]; if (moviePath) { //Creamos un NSURL y lo cargamos en musica NSURL *movieURL = [NSURL fileURLWithPath:moviePath]; video = [[MPMoviePlayerController alloc] initWithContentURL:movieURL]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayPreloadedVideo:) name:MPMoviePlayerLoadStateDidChangeNotification object:video]; }
![Page 207: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/207.jpg)
8.Preloading video
- El método que añadimos para atender a esa notificación
-(void)displayPreloadedVideo:(NSNotification*)note{ [self.view addSubview:video.view]; float h = self.view.bounds.size.height/2; float w = self.view.bounds.size.width; [video.view setFrame:CGRectMake(0, h, w, h)]; }
![Page 208: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/208.jpg)
9.Background Processes
- Una aplicación puede reproducir audio incluso si no es la aplicación activa.
- Para configurar este tipo de proceso de segundo plano debemos añadir a el fichero Info.plist de nuestro proyecto el correspondiente modo de background. Para el lo añadimos un campo más con el valor UIBackgroundModes. La clave que corresponde con la reproducción de audio en segundo plano es App plays audio
![Page 209: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/209.jpg)
9.Background Processes
- Para que la aplicación pueda reproducir audio en segundo plano deberemos cambiar la categoría de AVAudioSession.
- La categoría que permite reproducir audio en segundo plano es AVAudioSessionCategoryPlayback
NSString *musicPath = [[NSBundle mainBundle] pathForResource:@"music" ofType:@"mp3"]; if (musicPath) { //Creamos un NSURL y lo cargamos en musica NSURL *musicURL = [NSURL fileURLWithPath:musicPath]; //Cambiamos la categoria para reproducir audio en segundo plano [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
musica = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil]; [musica setDelegate:self]; }
![Page 210: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/210.jpg)
10.Guidelines for background execution
- Hay algunas reglas que Apple nos dice que debemos de seguir en el caso de las aplicaciones que tienen ejecución en segundo plano. Algunas de estas son:
- No uses OpenGL ES, el sistema operativo termina el proceso por la elevada carga
- No actualices tus vistas, el usuario no puede verlas
- Libera recursos cuando se produzca una llamada de low-memory warning
![Page 211: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/211.jpg)
11.Other forms of background execution
- Además de la reproducción de audio en segundo plano hay otros dos modos de ejecución:
- VOIP (Voice over internet protocol)
- Registers for location updates
![Page 212: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/212.jpg)
12.Low-level APIs
- En este tema hemos visto la forma más sencilla de reproducir vídeo y audio utilizando la API de alto nivel
- Si queremos hacer cosas más avanzadas como recodificar, aplicar filtros, efectos o lo que necesitemos deberemos utilizar las APIs de bajo nivel
- Usaremos AudioToolbox y CoreAudio para los sonidos
- Usaremos CoreVideo para el vídeo
![Page 213: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/213.jpg)
13.Audio Recording
- Podemos grabar audio utilizando la clase AVAudioRecorder
- Vamos a modificar nuestro ejemplo para añadir :
- Un botón grabar que nos permita grabar
- Un botón play que reproduzca el último archivo grabado
![Page 214: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/214.jpg)
13.Audio Recording
- Punteros necesarios
AVAudioPlayer *grabadoPlayer; AVAudioRecorder *grabadoRecorder; bool grabando;
-(IBAction)grabar:(id)sender;-(IBAction)reproducir:(id)sender;
![Page 215: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/215.jpg)
13.Audio Recording-(IBAction)grabar:(id)sender{ if (!grabando) { //Settings de grabar NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] initWithCapacity:10]; [recordSettings setObject:[NSNumber numberWithInt: kAudioFormatLinearPCM] forKey: AVFormatIDKey]; [recordSettings setObject:[NSNumber numberWithFloat:44100.0] forKey: AVSampleRateKey]; [recordSettings setObject:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey]; [recordSettings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey]; [recordSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey]; [recordSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey]; //Ponemos la sesion en modo grabación AVAudioSession *audioSession = [AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSessionCategoryRecord error:nil]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *recDir = [[paths objectAtIndex:0] stringByAppendingFormat:@"/%@", @"fichero"]; NSURL *url = [NSURL fileURLWithPath:recDir]; if (grabadoRecorder!=nil) { [grabadoRecorder stop]; [grabadoRecorder release]; } grabadoRecorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:nil]; if ([grabadoRecorder prepareToRecord] == YES) { grabando=true; [sender setTitle:@"Parar grabación" forState:UIControlStateNormal]; [grabadoRecorder record]; } } else { grabando=false; [sender setTitle:@"Grabar" forState:UIControlStateNormal]; [grabadoRecorder stop]; }}
![Page 216: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/216.jpg)
13.Audio Recording
-(IBAction)reproducir:(id)sender{ //Ponemos la sesion en modo reproducción AVAudioSession *audioSession = [AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *recDir = [[paths objectAtIndex:0] stringByAppendingFormat:@"/%@", @"fichero"]; NSURL *url = [NSURL fileURLWithPath:recDir]; if (grabadoPlayer!=nil) { [grabadoPlayer stop]; [grabadoPlayer release]; } grabadoPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; [grabadoPlayer play];}
- Método de reproducción
![Page 217: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/217.jpg)
26.Push Notifications and Networking
![Page 218: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/218.jpg)
1.Push Notifications
- Push Notifications, mecanismo para enviar notificaciones a los usuarios que tengan instalada nuestra aplicación
- Podemos mostrar un mensaje corto
- Podemos reproducir un sonido
- Podemos cambiar el badge de el icono de la aplicación
![Page 219: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/219.jpg)
1.Push Notifications
- Esquema de Push Notification
![Page 220: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/220.jpg)
2.Anatomy of a Push Notification
- Una notificación básica{ "aps": { "alert": "Hello, world!", "sound": "default" }}
- Configurando también el botón de abrir la notificación{ "aps": { "alert": { "action-loc-key": "Open", "body": "Hello, world!" }, "badge": 2 }}
- Como lo usaremos
{"aps":{"alert":"Hello, world!","sound":"default"}}
![Page 221: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/221.jpg)
3.Provisioning Profiles
- Para habilitar push notifications en tus aplicaciones, necesitan ser firmadas con un provisioning profile que esté configurado para push.
- Tu servidor necesita firmar las comunicaciones con los servidores APNS mediante un certificado SSL
- Hay dos tipos de push server certificates:- Development- Production
![Page 222: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/222.jpg)
4. Generating the Certificate Signing Request (CSR)
- Abrir keychain
- Solicitar un certificado para una autoridad de certificación
![Page 223: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/223.jpg)
4. Generating the Certificate Signing Request (CSR)
![Page 224: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/224.jpg)
4. Generating the Certificate Signing Request (CSR)
![Page 225: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/225.jpg)
4. Generating the Certificate Signing Request (CSR)
![Page 226: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/226.jpg)
5. Making App ID and SSL Certificate
![Page 227: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/227.jpg)
5. Making App ID and SSL Certificate
![Page 228: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/228.jpg)
5. Making App ID and SSL Certificate
![Page 229: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/229.jpg)
5. Making App ID and SSL Certificate
![Page 230: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/230.jpg)
5. Making App ID and SSL Certificate
- Una vez descargado el certificado.cer hacer doble click y instalarlo
- Después abriremos de nuevo KeyChain, buscamos el certificado y le damos a detalle
- Veremos los dos, el certificado y la clave privada
- Seleccionar los dos y exportamos como un fichero.p12
![Page 231: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/231.jpg)
5. Making App ID and SSL Certificate
![Page 232: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/232.jpg)
5. Making App ID and SSL Certificate
- Convertimos el certificado en un fichero .pem
openssl pkcs12 -in Certificado.p12 -out Certificado.pem -nodes
![Page 233: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/233.jpg)
6. Simple PHP Server
- Subimos los ficheros:
- ck.pem generado- simplepush.php
- Tendré acceso desde:
http://www.atomicflavor.com/PushNotification/simplepush.php
![Page 234: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/234.jpg)
7. Simplepush.php<?php
// Put your device token here (without spaces):$deviceToken = '0f744707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bbad78';
// Put your private key's passphrase here:$passphrase = 'curso';
// Put your alert message here:$message = 'My first push notification!';
////////////////////////////////////////////////////////////////////////////////
$ctx = stream_context_create();stream_context_set_option($ctx, 'ssl', 'local_cert', 'Certificado.pem');stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server$fp = stream_socket_client(! 'ssl://gateway.sandbox.push.apple.com:2195', $err,! $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)! exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
// Create the payload body$body['aps'] = array(! 'alert' => $message,! 'sound' => 'default'! );
// Encode the payload as JSON$payload = json_encode($body);
// Build the binary notification$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server$result = fwrite($fp, $msg, strlen($msg));
if (!$result)! echo 'Message not delivered' . PHP_EOL;else! echo 'Message successfully delivered' . PHP_EOL;
// Close the connection to the serverfclose($fp);
![Page 235: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/235.jpg)
8. Simple iPhone Client
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{! self.window.rootViewController = self.viewController;! [self.window makeKeyAndVisible]; ! // Let the device know we want to receive push notifications! [[UIApplication sharedApplication] registerForRemoteNotificationTypes:! ! (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; return YES;}
- Nueva single view application
- Hacemos que la app se registre para recibir push notifications
![Page 236: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/236.jpg)
8. Simple iPhone Client
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{! self.window.rootViewController = self.viewController;! [self.window makeKeyAndVisible]; ! // Let the device know we want to receive push notifications! [[UIApplication sharedApplication] registerForRemoteNotificationTypes:! ! (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; return YES;}
- Nueva single view application
- Hacemos que la app se registre para recibir push notifications
![Page 237: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/237.jpg)
8. Simple iPhone Client
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{! self.window.rootViewController = self.viewController;! [self.window makeKeyAndVisible]; ! // Para que el dispositivo reciba push notifications! [[UIApplication sharedApplication] registerForRemoteNotificationTypes:! ! (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; return YES;}
- Nueva single view application
- Hacemos que la app se registre para recibir push notifications
![Page 238: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/238.jpg)
8. Simple iPhone Client
- Nos hacen falta algunos métodos más
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{! NSLog(@"My token is: %@", deviceToken);}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error{! NSLog(@"Failed to get token, error: %@", error);}
![Page 239: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/239.jpg)
9. Create Provisioning Profile
- Ahora vamos a crear el provisioning profile y a instalarlo en el XCode
- A continuación podremos ejecutar nuestra app en el dispositivo
- Vemos el token del dispositivo y modificamos el php del servidor para que la notificación se envíe a ese dispositivo
- Ya podemos enviar nuestra primera push notification desde el servidor y recibirla en el dispositivo
![Page 240: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/240.jpg)
¿COMO CONTINUO EL CAMINO PARA CONVERTIRME EN UN
PROGRAMADOR NINJA?
Objective CCocoaQuartz
HTML5Javascript
CSS
OpenGL ES 1.5OpenGL ES 2.0
GLSL
PHPMySQLSQLite
![Page 241: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/241.jpg)
LIBROS RECOMENDADOS EDITORIAL APRESS
![Page 242: iOS Avanzado](https://reader030.fdocuments.co/reader030/viewer/2022012819/54558938b1af9f61728b4898/html5/thumbnails/242.jpg)
Miguel José García [email protected] : @miguelgarciacorhttp://www.atomicflavorgames.comhttp://www.atomicflavor.com
CONTACTO