Programación para iOS

Bibliografía

  • Universidad de Stanford. (http://www.stanford.edu/class/cs193p/cgi-bin/index.php)
  • Developer Center (http://developer.apple.com/iphone/library/navigation/index.html

https://github.com/jorgevila/ios-playground

Introducción

iOS

  • Gran curva de aprendizaje

  •  Hay que aprender a utilizar Cocoa frameworks (UIKit, etc)

  • También iPhone frameworks

  • Un nuevo IDE: XCode y nuevas herramientas Interface Builder, StoryBoard, Instruments.

  • Lenguajes de programación: Objective C / Swift

  • Diseñar iconos y gráficos específicos para la aplicación.

iOS

Introducción iOS

  • Versión reducida de distribución BSD sin shell
  • Aplicaciones desarrolladas con Objective-C / Swift
  • UI basada en UIKit (obj-C framework)
  • Librerías disponibles: cocoa-touch (cocoa for mac)

Objective-C

  • Capa desarrollada sobre C
  • Utilizada principalmente sobre MAC OS X, iPhone OS, GNUStep Compiled with GCC 4.0 (with objective-C support)
  • Desarrollada por NextStep 

Entorno

y todo, sólo para Mac

Arquitectura

Cocoa Touch es la base inicial de cualquier proyecto, contiene el framework UIKit

Obj-C librería gráfica

Audio / Vídeo / Animaciones

Librerías para servicios básicos: red, SQL, etc

Librerías para gestión de memoria, threads

Está diseñado para no bajar de nivel en la pila si no es realmente necesario implementar un comportamiento realmente novedoso.

Guía de buenas prácticas

  • Reducir complejidad
  • Iconos / imágenes adaptadas a cada dispositivo
  • Toda apliación debe guardar su estado
  • No bloquear la música
  • Tiempo se arranque mínimo

Se puede...

Acceder a la cámara

Obtener la posición

Eventos de acelerómetro y movimiento

Acceder al sonido

Guardar datos en el móvil: SQLite DB

Iniciar una llamada

Acceder a los contactos

Utilizar un WebView (HTML/JS)

Background tasks (>iOS7)

Notificaciones

Recursos: cámara

  • Se utiliza el UIImagePickerController
  • También para seleccionar imágenes de la galería
  • Capturar vídeo

    Introducción al esquema de Licencias, AppStore, etc.

Para publicar una App

  • Desarrollar Apps es gratuito, publicarlas no.
  • Modelos de licencia de desarrollo:

Pública: 99$ - 100 dispositivos TEST y ad-hoc

Privada: 299$ - Entidad de más de 500 empleados

Universitaria: Gratis – 200 dispositivos TEST 

¿Y cuanto se puede ganar?

  • Si es gratis, nadie saca nada (ni te cobran)
  • Puedes poner anuncios con iAd (y sacar beneficio por click)
  • Si es de pago el 30% para Apple y el 70% para el desarrollador (-IVA)
  • Compras In-App

¿cómo publico una aplicación?

Se utiliza iTunes Connect:

  • Establecer usuarios: Admin, técnico, finanzas, etc.
  • Firmar Contrato.
  • Proveer información de la aplicación: nombre, screenshots, palabras clave, rating, etc.
  • Enviar …
  • Y rezar para que la aprueben ;)

Antes habrá que probarla

Simulador: No es necesaria licencia.

Sistema de instalación Ad-Hoc (Test):

  • Se utiliza el iPhone Provisioning Portal.
  • Mediante certificados.
  • Apple firma la aplicación y así se asegura que no se sobrepasa el número de dispositivos.

Text

Recapitulando: flujo de aplicación

Recap: Qué necesito?

Referencia

Diseño

Ref

Estadísticas relevantes

  • Lenguaje orientado a objetos
  • Sintaxis -supuestamente- clara y simple
  • Paso de mensajes entre objetos
  • Casi todo definido en runtime
  • Cocoa libraries -> GUI

Stepstone->NextStep->Apple

Primitive

Data types

int, short, long

float, double

char

BOOL = boolean (YES|NO)

Punteros

Como en C

 

&i -> dirección en memoria de la variable i

 

Puntero:

int *addressofi = &i;

Global y static

global variables definidas al principio del fichero

 

static variables con el keyword "static"

 

Keywords

Conditionals

if / else if / else

for

while

break

continue

do-while

for in loop (Obj-C 2.0)

 

 

for(int i=0; i< 22; i++) {

     printf(“Checking i=“@d\n”, i);
     if(i+90 == i*i) 
     {
        break;
     }
}
for(Item_Type  *item in  Collection_of_Items)  {

       //do whatever with the item
       Nslog(@”  Looking now at %@”,  item);

// %@ converts anything to string
}

Funciones

return_type functionName(type v1, type v2, ...)
{
    // code of function
}

//Example:

void showMeInfo(int age)
{
   printf("you are %d years old", age); // or NSLog()
}

/////////////////////// Function - Pass by reference

return_type functionName(type v1, type *v2, ….)
{
   //code of function
}


//Example – call above
int v1 = 2;
int v2 = 3;
functionName(v1, &v2);

Main

#import <whatever/what.h>

int main(int argc, const char *argv[])
{
   @autoreleasepool {
         //your code here******* 
     
          return 0;
    }

}

Automatic Reference Counting %= automatic garbage collection de java

Se acabaron los memory leaks con @autoreleasepool

Text output

žprintf() 

printf(“Hi Lynne”);   //this is actual C code

 

žNSLog()

NSLog(@”Hi Lynne”);  //this is strictly Objective-C

r

Aquí empieza lo diferente

Objects

Clases: interfaz

Métodos

Java:

public void function(int x, int y, char z) {};

Object.function(x, y, z);

Objective C:

-(void) method:(int)x, (int)y, (char)z; 

[Object function:x, y, z]; 

// aplicar function al objeto Object con los parámetros x,y,z

- (int) multiplyThis:(int) x ByThis:(int) y AndThis:(int) z;

  Method name is multiplyThis:ByThis:AndThis

Métodos: +,-

Los métodos se declaran con + o -

 

+ -> "class method" , como métodos estáticos de java

 

- -> "instance methods", métodos públicos en una instancia de clase/objeto

Properties

Para declarar setter/getter de variables


// Person.h
@interface Person : NSObject{
          //don’t need to declare the variables here
          // ---they are done with @property}
@property float heightInMeters;    //will create setter and getter method for this var
@property float weightInKilos;    //will create setter and getter method for this var 
- (float) bodyMassIndex;   //instance method
   
@end

// Person.m
#import “Person.h”
@implementation Person 
@synthesize heightInMeters, weightInKilos;

- (float) bodyMassIndex
  { return weightInKilos / (heightInMeters * heightInMeters); }

Properties

@property (nonatomic) <type> <property name> 
@property (strong or weak) <type which is a pointer to an object> <property name>
@property (getter=<getter name>) ...
@property (readonly) ... & @property (readwrite) ...

 

@synthesize <prop name> = _<prop name> (only if you implement both setter and getter) 

Clases: Implementación

Clases: instancia

ClassName   *object = [[ClassName alloc] init]; 
ClassName   *object = [[ClassName alloc]  initWith* ];
      NSString* myString = [[NSString alloc] init];


alloc -> reserva memoria e instancia el objeto.

init -> inicializa valores en el nuevo objeto.

 

Algunas clases crean un método específico de inicialización.

ClassName *object = [ClassName method_to_create];
NSString* myString = [NSString string];

 

Clases: instancia

A partir de otros objetos

NSString’s - (NSString *)stringByAppendingString:(NSString *)otherString;
NSString’s & NSArray’s - (id)mutableCopy;
NSArray’s - (NSString *)componentsJoinedByString:(NSString *)separator;


Using class methods to create objects
NSString’s + (id)stringWithFormat:(NSString *)format, ...
UIButton’s + (id)buttonWithType:(UIButtonType)buttonType;
NSMutableArray’s + (id)arrayWithCapacity:(int)count;
NSArray’s + (id)arrayWithObject:(id)anObject;

 

Destroying a class object = nil; // null

Clases: self

self == this

//some code inside a method of a class

//method class to getter for the variable heightInMeters

float h = [self  heightInMeters];  

 

//another example a method in a class that adds itself (object) to an array that is //passed

-(void) addYourselfToArrayLNSMutableArray *) theArray

   {  [theArray  addObject:self];    }

Mensajes

Mensajes

Memoria: 

alloc - release

init - dealloc

init - dealloc

Ciclo de vida de un objeto

Ciclo de vida completo

Cada referencia a un objeto incrementa el contador en memoria, y no se libera mientras exista una referencia.

alloc - release

alloc - release

Memory Leak

  • Si hacemos "alloc" o "retain" mantenemos una referencia al objeto, si no es "weak".
  • Si mantienes un objeto, nadie puede liberarlo de memoria mientras no hagamos release
  • Para todo "alloc" o "retain" debemos enviar un "release", o tenemos un memory leak

Introspección

Todo objeto que hereda de NSObject: 

isKindOfClass: herencia

isMemberOfClass: tipo de clase de objeto, no herencia

Obtener una clase es un método de clase: if ([obj isKindOfClass:[NSString class]]) {}

respondsToSelector: devuelve si un objeto responde a un método.

Directiva @selector() (SEL)

if ([obj respondsToSelector:@selector(shoot)]) {  [obj shoot]; }

Arrays

  • NSArray/NSMutableArray contiene un número fijo/variable de objetos
  • El array mantiene siempre una referencia a sus elementos, de manera que evita que sean liberados de memoria 
//Init the mutable array with an initial capacity of 5 elements
NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:5];

//Init a UIView element
UIView* myView = [[UIView alloc] init];

//Add the new view to the array
[array addObject:myView]; // myView has received here a "retain" message
//Release the object (no automatic deallocation because array keeps the ownership)
[myView release];

@[@“a”,@“b”] == [[NSArray alloc] initWithObjects:@“a”,@“b”,nil].

myArray[index] == [myArray objectAtIndex:index].

setMethod

setMethod

copy - autorelease

DataTypes

NSInteger number;

NSUInteger unsignedNumber

NSString

Usado en iOS en vez de char* type

NSString *theMessage = @"hola";

 

NSUInteger charCount= [theMessage length];

 

if([string_1 isEqual: string_2]) { // equal strings }

NSInteger

Strings con @

@”Hello World”; 

NSString *myString = @”Hello World”;
int len    =  [myString  length];

int len = [@”Hello World”   length];

NSString *myString = [[NSString alloc] initWithString:@”Hello World”];
int len = [myString  length];

// Formatting output with NSLog
int a = 1; 
float b =  33.22; 
char c = ‘A’;
NSLog(@”Integer  %d  Float:  %f   Char:  %c”, a, b, c);

NSString inmutable

NSString es inmutable. Normalmente las funciones envían un mensaje a un NSString que devuelve un NSString nuevo.

self.display.text = [self.display.text stringByAppendingString:digit];

NSMutableString

Versión de NSString modificable para realizar modificaciones sin crear un nuevo objeto

 

Más tipos

  • NSValue: wrapper para otros tipos como structs de C
  • NSData: almacén de datos en binario
  • NSDate: NSDateFormatter, NSDateComponents, ...
  • NSNumber: wrapper para int, float, double, BOOL, enum. NSNumber *three = @3; *three = @(3)

NSArray

  • array inmutable de punteros a objetos
  • count = número de items
  • objectAtIndex:i = item i del array (empezando en 0)
NSArray   *thearray = [NSArray arrayWithObjects:o1,o2,o3,o4, nil]; 

//get element
[thearray objectAtIndex:0];   //element at index 0

//Example

NSDate *now = [NSDate date];
NSDate *tomorrow = [now dateByAddingTImeInterval:24.0*60.0*60.0]; //add a day
NSDate *yesterday = [now dateByAddingTimeInterval:-24.0*60.0*60.0]; //minus a day

//array of Dates
NSArray  *dateList  = [NSArray arrayWithObjects:now, tomorrow, yesterday];

//get elements in array
NSDate *first = [dateList objectAtIndex:0];  


NSUInteger dateCount = [dateList count];
for(int i=0; i<dateCount; i++)
   {   NSDAte *d = [dateList objectAtIndex:i];
        NSLog(@” Date is %@”, d);
   }


for(NSDate *d in dateList) 
   {   NSDAte *d = [dateList objectAtIndex:i];
        NSLog(@” Date is %@”, d);
   }

NSMutableArray

  • array mutable de punteros a objetos
  • count = número de items
  • objectAtIndex:i = item i del array (empezando en 0)
  • addObject:obj
  • insertObject:obj
  • removeObjectAtIndex:i
NSMutableArray   *thearray = [NSArray arrayWithObjects:o1,o2,o3,o4, nil]; 

//get element
[thearray objectAtIndex:0];   //element at index 0

otros

  • NSDictionary: hash table
  • NSMutableDictionary
  • NSSet/NSMutableSet
  • NSOrderedSet/NSMutableOrderedSet
+ (id)dictionaryWithObjects:(NSArray *)values forKeys:(NSArray *)keys;
+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;

//Creation example:
NSDictionary *base = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithInt:2], @“binary”,
    [NSNumber numberWithInt:16], @“hexadecimal”, nil];

Can create with this syntax: @{ key1 : value1, key2 : value2, key3 : value3 } 
NSDictionary *colors = @{ @“green” : [UIColor greenColor],
    @“blue” : [UIColor blueColor],
    @“red” : [UIColor redColor] };

Property List

Colección de colecciones

 

Cualquiera de las clases NSArray, NSDictionary, NSNumber, NSString, NSDate, NSData

 

Se utiliza para ficheros de propiedades:

[plist writeToFile:(NSString *)path atomically:(BOOL)] //plist is NSArray or NSDictionary

NSUserDefaults

Almacenamiento de property lists en un NSDictionary, persistente entre ejecuciones de la aplicación.

 

[[NSUserDefaults standardUserDefaults] setArray:rvArray forKey:@“RecentlyViewed”];

// Write after batch of changes
[[NSUserDefaults standardUserDefaults] synchronize];

 

UIKit

UIKit is the framework with all graphical elements for native iphone apps 

UIViewController

UIViewController es el controlador para Navegación y Tabs

+UIKit

+UIKit

UIButton

UILabel

UIFont

UIColor

UITextView

UIColor

 

Objeto que representa un color.

Se puede inicializar con RGB, HSB, etc

Pueden tener un alpha: 

UIColor *color = [otherColor colorWithAlphaComponent:0.3]).

Hay una lista de colores estándar: 

[UIColor greenColor];

[UIColor lightTextColor]

UIFont

 

UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];

UIFontDescriptor: + (UIFont *)fontWithDescriptor:(UIFontDescriptor *)descriptor size:(CGFloat)size; 

Bold from UIFontTextStyleBody preferred font

UIFont *bodyFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
UIFontDescriptor *existingDescriptor = [bodyFont fontDescriptor];
UIFontDescriptorSymbolicTraits traits = existingDescriptor.symbolicTraits;
traits |= UIFontDescriptorTraitBold;
UIFontDescriptor *newDescriptor = [existingDescriptor fontDescriptorWithSymbolicTraits:traits];
UIFont *boldBodyFont = [UIFont fontWithFontDescriptor:newDescriptor size:0];

NSAttributedString

Controla las características de una fuente en pantalla (color, outline, stroke, underline, etc).

NSAttributedString no es un NSString : - (NSString *)string;

 

NSMutableAttributedString
- (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range;
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range;
- (void)removeAttribute:(NSString *)attributeName range:(NSRange)range;

Ejemplos:

UIButton’s - (void)setAttributedTitle:(NSAttributedString *)title forState:...;

UILabel’s @property (nonatomic, strong) NSAttributedString *attributedText; UITextView’s @property (nonatomic, readonly) NSTextStorage *textStorage;

UILabel

Se puede utilizar a través de la propiedad text.
pero también:

@property (nonatomic, strong) NSAttributedString *attributedText;

 

Este atributo no es mutable, por lo que para modificarlo hay que utilizar una copia.

NSMutableAttributedString *labelText = [myLabel.attributedText mutableCopy]; [labelText setAttributes:...];
myLabel.attributedText = labelText;

UITextView

 

UILabel multi-línea, editable, scroll, etc. Texto y attributos utilizando NSMutableAttributedString

 

@property (nonatomic, readonly) NSTextStorage *textStorage;

 

NSTextStorage hereda de NSMutableAttributedString.

 

iOS SDK

Capas

Cocoa Touch

Foundation

  • Bases de datos / Colecciones
  • Wrappers para servicios del sistema

UIKit

  • Clases de interfaz gráfico
  • Runtime de la aplicación
  • Gestión de eventos
  • APIs de hardware

Otros: Mapkit, Message

a bajo nivel

Media

  • Soporte de imágenes y video
  • Animación con OpenGL
  • Acceso a fotos y videos del dispositivo

Core Services

  • Localización (usa Core Location Framework)
  • SQLite (base de datos ligera) (Interfaz en C)

Core OS

  • Framework para trabajar con protocolos de red
  • Core Location Framework

Patrones de diseño

Hay 6 patrones de diseño importantes

  • Modelo-Vista-Controlador
  • Target-Action
  • Delegación
  • Gestión de memoria
  • Block objects
  • Hilos y concurrencia

 

Los patrones no son más que maneras de hacer las cosas. Hay que adaptarse a ellos.

Delegación

Alternativa a hacer subclases (Objective-C NO es multiherencia)

En UIKit Framework se hace un uso intensivo

  • UIApplicationDelegate
  • UITableViewDelegate
  • UITextFieldDelegate

Básicamente, una clase es asignada como 'delegada' para realizar algunas funciones de otra clase (Patrón de Decoración)

Ciclo de Vida

Ciclo de Vida

Ciclo de Vida

UIApplicationDelegate

 

Cada aplicación tiene un delegado que cumple este protocolo, para dotar de comportamiento a la aplicación

Métodos importantes:

•applicationDidFinishLaunching

•applicationWillTerminate

•applicationDidReceiveMemoryWarning

Target Action

Una acción (método) de un objeto (target) es invocada al realizar algún tipo de interacción (event)

En UIKit Framework la clase UIControl se encarga de encapsular estos tres elementos

En iOS una clase o subclase de UIControl puede realizar diferentes acciones en diferentes objetos en respuesta al mismo evento

 

MVC

MVC

Controlador

UIApplication

Gestiona el bucle de eventos y coordina otros aspectos del comportamiento de la aplicación. Notifica al objeto delegado cuando ocurren eventos en la aplicación

Objeto delegado

Inicializa la aplicación y presenta la ventana de la interfaz. Además se encarga de tratar los eventos de la aplicación, aviso de memoria, la aplicación va a terminar...

View Controllers objects (UIViewController)

Se encargan de la presentación de cada vista, y de gestionar la interacción del usuario con la interfaz, así como modificar el modelo de datos de la aplicación. 

Vistas

UIWindow

Presentar las vistas y mandar los eventos de la interfaz al controlador.

Vistas, controles y capas

Dibujan la representación de los datos, controles y el patrón target-action.

Modelos de datos

Clases e información de la aplicación. 

Example UIApplication

r

XCode

Modificación sintáctica: id <MyProtocol> obj, como el interfaz en Java

 

Protocol

@protocol Foo <xyz>
- (void)someMethod;
@optional
- (void)methodWithArgument:(BOOL)argument;
@required
// getter (only) is part of this protocol
@property (readonly) int readonlyProperty;
// getter and setter are both in the protocol 
@property NSString *readwriteProperty; 
- (int)methodThatReturnsSomething;
@end

// importing the header file that declares the Foo @protocol 
#import “Foo.h” 
@interface MyClass : NSObject <Foo> 
// MyClass is saying it implements the Foo @protocol
// (do not have to declare Foo’s methods again here, 
// it’s implicit that you implement it)
@end 

- (void)giveMeFooObject:(id <Foo>)anObjectImplementingFoo;
@property (nonatomic, weak) id <Foo> myFooProperty; // properties too!

Comienza con el carácter ^

Es un conjunto de código ejecutable y referenciable como objeto

Block

[aDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
    NSLog(@“value for key %@ is %@”, key, value);
    if ([@“ENOUGH” isEqualToString:key]) {
       *stop = YES; }
}];

View Controllers

¿Qué es un controlador?

Función:

  • Carga la vista y los valores iniciales
  • Recibe los eventos de la interfaz
  • Gestiona la rotación: (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation
  • Libera los recursos relacionados con la vista

 

Clases

UIViewController

Puede contener:

  • Variables de tipo del modelo de datos
  • Variables 'outlets' (IBOutlet) para conectar con objetos de la vista
  • Acciones 'outlets' (IBAction) para conectar con objetos de control de la vista
  • Otros métodos auxiliares

Ref

Ciclo de vida de un controlador

  • initWithNibName: Configuración no relacionadas con la vista
  • viewDidLoad: Valores iniciales (relacionados con la vista)
  • viewWillAppear: La vista va a aparecer
  • viewWillDisappear: Guardar el estado
  • viewDidUnload: Liberar recursos

ViewController LifeCycle

awakeFromNib -> Instanciado desde el storyboard

viewDidLoad -> IBOutlets creados

   cuando se posicionan las vistas
   viewWillLayoutSubviews: viewDidLayoutSubviews:

   cuando aparece y desaparece el controlador

   viewWillAppearviewDidAppear:

       cuando cambia la posición (rotación)

       viewWillLayoutSubviewsviewDidLayoutSubviews:
       si es por rotación, también se reciben

       [will/did]Rotate[To/From]InterfaceOrientation

   viewWillDisappear: viewDidDisappear:

en caso de falta de memoria -> didReceiveMemoryWarning

IBAction

Acción que se puede ejecutar en respuesta a un evento.

 

- (IBAction)exampleAction:(id)sender;

 

Se enlaza con una acción directamente en el interfaz

IBOutlet

Referencia a un elemento gráfico.

 

@property (weak, nonatomic) IBOutlet UITextField *textField;

 

 

Composición

UINavigationController

Gestiona la barra de navegación (UINavigationBar)

  • Botón 'Atrás'
  • Título
  • Otros controles
  • Pila controllers (last-in,first-out)

UINavigationItem

 

Todos los controladores tienen una variable UINavigationItem

Personaliza la barra superior cuando el controlador está en el top de la pila (visible)

UIBarButtonItem *lftBoton = [UIBarButtonItem alloc];
[lftBoton initWithTitle:@”Dale!” 
   style: UIBarButtonItemStyleBordered 
   target:self action:@selector(metodoBoton:)]; 
self.navigationItem.leftBarButtonItem =lftBoton; 
[lftBoton release];

Estructura:

NSString *title;
UIBarButtonItem *leftBarButtonItem, *rightBarButtonItem;
UIView *titleView;
NSString *backButtonTitle;

Example UINavigationViewController

Composición

UITabBarController

Gestiona la barra de pestañas (UITabBar)

  • Vistas en un array

UITabBarItem

 

Todos los controladores tienen una variable UINavigationItem

Personaliza la barra superior cuando el controlador está en el top de la pila (visible)

UITabBarItem *item = [[UITabBarItem alloc]
    initWithTabBarSystemItem:UITabBarSystemItemBookmarks tag:0];
self.tabBarItem = item; 
[item release];

Estructura:

NSString *title;
UIImage *image;
NSString *badgeValue

Combinando controladores

 

Navegación

Las escenas se conectan con  segues, que represetan una transición entre dos view controllers.

Navegación

Ref

Tipos de Segue

Show/Push: se añade nuevo contenido a la pila

Show detail: añade nuevo contenido o reemplaza el existente.

Present modally: muestra un controlador modal como "hijo" del actual, que tiene la responsabilidad sobre el mismo

Popover presentation: se presenta un popover sobre una vista del view controller. 

Custom: una transición realizando sobre UIStoryboardSegue.

Unwind: reverse navigation.

Navegación condicional

Se implementa en código utilizando:
- (void)performSegueWithIdentifier:(NSString *)segueId sender:(id)sender;
 sender -> es el iniciador del evento

 

- (IBAction)rentEquipment
{

    if (self.snowTraversingTalent == Skiing) {
        [self performSegueWithIdentifier:@“AskAboutSkis” sender:self];

    } else {
        [self performSegueWithIdentifier:@“AskAboutSnowboard” sender:self];

} } 

Segue por código

 

 Se transmite la información que necesite al siguiente controlador, y se cede el control.

 

 

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if ([segue.identifier isEqualToString:@“DoSomething”]) {
        if ([segue.destinationViewController isKindOfClass:[DoSomethingVC class]]) {


            DoSomethingVC *doVC = (DoSomethingVC *)segue.destinationViewController;
            doVC.neededInfo = ...; }

} }

Se puede condicionar

 

Si se responde NO a este método, el segue no continuaría. Por ejemplo, para validación de datos.

 


- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
    if ([segue.identifier isEqualToString:@“DoAParticularThing”]) {
        return [self canDoAParticularThing] ? YES : NO;
    }
}

Unwind segue


// Target viewcontroller
- (IBAction)myUnwindAction:(UIStoryboardSegue*)unwindSegue

Ejemplo Navegación

ViewController

r s

Vistas modales

Permiten mostrar una nueva pantalla para coger información, presentar de forma distinta un contenido, etc.

Vistas modales

Mostrar un controlador de forma modal

[self presentModalViewController:viewController animated:YES];

 

Ocultar un controlador

[self dismissModalViewControllerAnimated:YES];

Ref

Modal ViewController

- (void)add:(id)sender {
   // Create the root view controller for the navigation controller
   // The new view controller configures a Cancel and Done button for the
   // navigation bar.
   RecipeAddViewController *addController = [[RecipeAddViewController alloc] init];
 
   addController.modalPresentationStyle = UIModalPresentationFullScreen;
   addController.transitionStyle = UIModalTransitionStyleCoverVertical;
   [self presentViewController:addController animated:YES completion: nil];
}

Tablas

Ref

UITableView

UITableViewController

Protocolos

  • UITableViewDataSource
  • UITableViewDelegate (Apariencia y comportamiento)

Celdas (UITableViewCell)

Estilos

UITableViewController

Delegado de UITableViewDataSource y UITableViewDelegate, separando modelo y vista

UITableViewDelegate

 

–willDisplayCell:forRowAtIndexPath;

–willSelectRowAtIndexPath;

–didSelectRowAtIndexPath;

–accessoryTypeForRowWithIndexPath

– accessoryButtonTappedForRowWithIndexPath

UITableViewDataSource

 

–numberOfSectionsInTableView;

–numberOfRowsInSection:(NSInteger)section; *

–cellForRowAtIndexPath:(NSIndexPath *)indexPath; 

–InsertSections, deleteSections, reloadSections

–insertRowsAtIndexPaths...

UITableView Protocols

 

delegate controla cómo se muestra la tabla
dataSource proporciona los datos de la table

UITableViewController
es automáticamente un UITableView delegate y dataSource

@property (nonatomic, strong) UITableView *tableView;

( == self.view en UITableViewController!)

 

UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)sender
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
}

typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
} UITableViewCellStyle;

Hay que definir un UITableViewCell

UITableViewDataSource

- (UITableViewCell *)tableView:(UITableView *)sender
            cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
      
    UITableViewCell *cell;
    cell = [self.tableView 
            dequeueReusableCellWithIdentifier:@“Flickr Photo Cell”
            forIndexPath:indexPath];
    cell.textLabel.text = [self 
            getMyTitleForRow:indexPath.row 
            inSection:indexPath.section];
    return cell;
}

UITableViewDelegate




- (void)tableView:(UITableView *)sender didSelectRowAtIndexPath:(NSIndexPath *)path ! {!
    // go do something based on information about my Model! 
    // corresponding to indexPath.row in     indexPath.section
}

- (void)tableView:(UITableView *)sender
        accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {

    // Do something related to the row at indexPath,
    // but not the primary action associated with touching the row
}

UITableView Segue



- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
    // prepare segue.destinationController to display based on information
    // about my Model corresponding to indexPath.row in indexPath.section
}

El sender es un UITableViewCell

Datos

Sistema de Archivos

Cada aplicación tiene su propio conjunto de directorios

<Application Home>

MyApp.app

           MyApp

           MainWindow.nib

           SomeImage.png

       Documents

       Library

           Caches

     Preferences

Sólo pueden escribir en su directorio Home

Sistema de Directorios

NSPathUtilities.h → Conjunto de categorías para trabajar con rutas del sistema de archivos de una aplicación

 

Buscando el directorio Documents:

 

NSString *documentDirectory;

NSArray *paths = NSArray *paths = NSSearchPathForDirectoriesInDomains

          (NSDocumentDirectory, NSUserDomainMask, YES);

    documentsDirectory = [paths objectAtIndex:0];

Accediendo al bundle

Accediendo al bundle de la aplicación

NSBundle *bundle = [NSBundle mainBundle];

 

Obteniendo la ruta de un recurso en el bundle

NSBundle *bundle = [NSBundle mainBundle];

[bundle pathForResource:@”image” ofType:@”jpg”];

Property Lists

Es una manera de representar jerarquías simples de datos

Sólo soporta arrays, diccionarios, strings, fechas, enteros, dobles y booleanos

Una property list es una clase (array o diccionario) que engloba uno o varios objetos soportados

Representada con XML o con un binario (más compacto)

Se usa para una cantidad menor de unos pocos cientos de KBs

Property Lists

Métodos para escribir

- (BOOL)writeToFile:(NSString *)aPath atomically:(BOOL)flag;

- (BOOL)writeToURL:(NSURL *)aURL atomically:(BOOL)flag;

Métodos para leer

- (id)initWithContentsOfFile:(NSString *)aPath;

- (id)initWithContentsOfURL:(NSURL *)aURL;

Ejemplo de lectura  (en el caso de NSArray):

NSString *path = [[NSBundle mainBundle] pathForResource:@"places" ofType:@"plist"];

NSArray *placesArray = [NSArray initWithContentsOfFile:path];

Integradas en la aplicación o en la aplicación Settings

Normalmente, si tienen poco uso, se utilizarían las settings.

Clase NSUserDefaults

–Método de clase → +(id)standardUserDefaults

–Es una Property List

Ejemplo de uso (insertar valor y recuperarlo)

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

[defaults setObject:@”Pedro” forKey: @”name”];

NSString *nombre = [defaults stringForKey:@”name”];

Settings Bundle

Settings.bundle en tu aplicación sirve para añadir las preferencias a la aplicación Settings de iPhone/iPod/iPad

Muestra una pantalla con controles

Cada control tiene (al menos)

*Tipo (Type)

*Titulo (Title)

*Clave (Key)

Ref

XML

NSXMLParser - clase para parsear XML dirigido por eventos (como JAXP)

NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];

[parser setDelegate:self];

[parser setShouldProcessNamespaces:NO];

[parser setShouldReportNamespacePrefixes:NO];

[parser setShouldResolveExternalEntities:NO];

[parser parse]; //empieza a parsear

Iniciar un objeto NSXMLParser y asignarle un delegado

didStartElement → Guardar el tag y reservar memoria estructura

didEndElement → Guardar valores en la estructura

foundCharacters → Guardar valor del tag

JSON

NSJSONSerialization - clase para parsear JSON

 

 NSMutableDictionary *returnedDict = 

     [NSJSONSerialization JSONObjectWithData:data          

      options:kNilOptions error:&error];

O utilizando una librería como JSONKit

NSData* jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];

NSDictionary *resultsDictionary = [jsonData objectFromJSONData];

CoreData

Core Data no es un RDBMS, aunque utiliza SQLite por debajo.

 

Utiliza un NSManagedObjectContext, a partir de un UIManagerdDocument o el AppDelegate.

 

El modelo  se crea como un Data Model en el XCode.

CoreData

Insert/Delete un objeto:

NSManagedObjectContext *context = aDocument.managedObjectContext;
NSManagedObject *photo =
    [NSEntityDescription insertNewObjectForEntityForName:@“Photo”
    inManagedObjectContext:context];

[context deleteObject:photo];

Atributos:

- (id)valueForKey:(NSString *)key; !
- (void)setValue:(id)value forKey:(NSString *)key; !

El tipo es nil por defecto.

NSNumber para números, boolean; NSData para datos binarios, NSDate para fechas, NSSet para relaciones

CoreData

Queries: NSFetchRequest

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“Photo”];
 request.fetchBatchSize = 20;
 request.fetchLimit = 100;
 request.sortDescriptors = @[sortDescriptor];
 request.predicate = ...;
NSArray *photographers = [context executeFetchRequest:request error:&error];

NSPredicate:

NSString *serverName = @“flickr-5”;
 NSPredicate *predicate =
      [NSPredicate predicateWithFormat:@“thumbnailURL contains %@”, serverName];

// unique a photo in the database
@“uniqueId = %@”, [flickrInfo objectForKey:@“id”]  
// matches name case insensitively!
@“name contains[c] %@”, (NSString *)
// viewed is a Date attribute in the data mapping!  
@“viewed > %@”, (NSDate *) 
// Photo search (by photographer’s name)!
@“whoTook.name = %@”, (NSString *) 
// Photographer search (not a Photo search)
@“any photos.title contains %@”, (NSString *) 

CoreData y UITableView

NSFetchedResultsController enlaza un NSFetchRequest con UITableViewController. Normalmente se utiliza una @property para referenciar el NSFetchedResultsController

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@“Photo”];
 request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@“title” ...]];
 request.predicate = [NSPredicate predicateWithFormat:@“whoTook.name = %@”, photogName];
 NSFetchedResultsController *frc = [[NSFetchedResultsController alloc]
     initWithFetchRequest:(NSFetchRequest *)request
     managedObjectContext:(NSManagedObjectContext *)context
       sectionNameKeyPath:(NSString *)keyThatSaysWhichSectionEachManagedObjectIsIn
                cacheName:@“MyPhotoCache”];  // careful!

//UITableView
- (NSUInteger)numberOfSectionsInTableView:(UITableView *)sender
  {
      return [[self.fetchedResultsController sections] count];
}
  - (NSUInteger)tableView:(UITableView *)sender 
     numberOfRowsInSection:(NSUInteger)section
  {
      return [[[self.fetchedResultsController sections] 
          objectAtIndex:section] numberOfObjects];
}

- (UITableViewCell *)tableView:(UITableView *)sender
          cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
     UITableViewCell *cell = ...;
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
}

SQLite

Acceso a una Sqlite a bajo nivel.

#import <sqlite3.h>

sqlite3_open, sqlite3_prepare_v2, sqlite3_step
sqlite3_column_count, sqlite3_column_text
sqlite3_column_name, sqlite3_changes, sqlite3_last_insert_rowid, sqlite3_errmsg, sqlite3_finalize, sqlite3_close

Views and Gestures

Vistas

Una vista es una clase que hereda de UIView

Es parte de una jerarquía:

Una vista sólo tiene un padre - (UIView *)superview
Pero puede tener muchos hijos - (NSArray *)subviews
El orden importa (front-back)

UIWindow

UIView raíz de la jerarquía
En iOS sólo tenemos (normalmente) un UIWindow, no se trata de ventanas.

Vistas

Se construye gráficamente en Xcode, aunque se puede hacer por código.

- (void)addSubview:(UIView *)aView; // sent to aView’s (soon

- (void)removeFromSuperview; // sent to the view that is being removed 

 

La raíz de nuestro modelo es: @property view

UIViewCo@property (strong, nonatomic) UIView *view

Esta vista es el padre de nuestras vistas, la que sufre la rotación, se le añaden vistas hijo, etc.

Coordenadas

CGFloat
CGPoint: struct con 2 CGFloat (x,y)

CGPoint p = CGPointMake(34.5, 22.0);

CGSize: struct con 2 CGFloat (ancho, alto) 

CGSize s = CGSizeMake(100.0, 200.0);

CGRect: struct con CGPoint origen y size

CGRect aRect = CGRectMake(45.0, 75.5, 300, 500);

Coordenadas

Pixels por punto en la pantalla

@property CGFloat contentScaleFactor

Espacio ocupado

@property CGRect bounds;

Centro

@property CGPoint center;

Límites de la vista padre:

@property CGRect frame; 

Crear una vista

Normalmente se crean en el XCode, arrastrando una vista y modificándola en el Identity Inspector

 

También se puede crear por código:

CGRect labelRect = CGRectMake(20, 20, 50, 30);
UILabel *label = [[UILabel alloc] initWithFrame:labelRect]; 
label.text = @”Hello!”;
[self.view addSubview:label];

Custom View

Para crear nuestras propias vistas o manejar los eventos de una forma diferente.

Extender UIView y sobreescribir el método:

- (void)drawRect:(CGRect)aRect;

Se dibuja utilizando Core Graphics.

 

Actualizar mediante los métodos

- (void)setNeedsDisplay;

- (void)setNeedsDisplayInRect:(CGRect)aRect;

Transparencia

UIColor tiene la propiedad de alpha, que se puede modificar en el UIView backgrounnColor

@property BOOL opaque; debe de ser NO

@property CGFloat alpha en UIView modifica la transparencia de toda la vista.

@property (nonatomic) BOOL hidden; puede esconder completamente una vista

 

UILabel

Subview para dibujar text en una vista.

 

 

 

UILabel *scoreLabel = [ [UILabel alloc ] 
    initWithFrame:CGRectMake((self.bounds.size.width / 2), 0.0, 150.0, 43.0) ];
scoreLabel.textAlignment =  UITextAlignmentCenter;
scoreLabel.textColor = [UIColor whiteColor];
scoreLabel.backgroundColor = [UIColor blackColor];
scoreLabel.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size:(36.0)];

[self addSubview:scoreLabel];
scoreLabel.text = [NSString stringWithFormat: @"%d", score];

//How much space will a piece of text will take up when drawn?
CGSize textSize = [text size];

UIImageView

Crear una imagen a partir de un fichero de los recursos

UIImage *image = [UIImage imageNamed:@“foo.jpg”];

De un fichero o de datos raw

UIImage *image = [[UIImage alloc] initWithContentsOfFile:(NSString *)fullPath];
UIImage *image = [[UIImage alloc] initWithData:(NSData *)imageData];

 

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage                                             imageNamed:@"image Name"]] ;

@property (nonatomic) UIViewContentMode contentMode;

 

Controla el refresco de la pantalla.

UIViewContentMode {Left,Right,Top,Right,BottomLeft,BottomRight,TopLeft,TopRight}

UIViewContentModeScale{ToFill,AspectFill,AspectFit} UIViewContentModeRedraw -> repintar con cada cambio de límites

Default: UIViewContentModeScaleToFill 

Animaciones

Animaciones de propiedades de un UIView

  • frame

  • transform (translation, rotation, escale)

  • alpha (opacity)

Animación de apariencia (UI)

 

Animación dinámica (gravedad, fuerzas, alineamiento, etc)

UIView animation

Fade en 3 segundos sólo si se completa la animacion.

Animation class method in UIView
+ (void)animateWithDuration:(NSTimeInterval) duration 
    delay:(NSTimeInterval)delay 
   options:(UIViewAnimationOptions)options 
   animations:(void (^)(void))animations 
   completion:(void (^)(BOOL finished))completion; 

[UIView animateWithDuration:3.0 
   delay:0.0 
   options:UIViewAnimationOptionBeginFromCurrentState 
   animations:^{ myView.alpha = 0.0; } 
   completion:^(BOOL fin) { if (fin) [myView removeFromSuperview]; }];

UIView animation

UIViewAnimationOptions

BeginFromCurrentState 
AllowUserInteraction
LayoutSubviews
Repeat
Autoreverse
OverrideInheritedDuration
OverrideInheritedCurve
AllowAnimatedContent
CurveEaseInEaseOut
CurveEaseIn
CurveLinear

UIView Transiciones

Reemplazar una vista

+ (void)transitionFromView:(UIView *)fromView
                    toView:(UIView *)toView
                  duration:(NSTimeInterval)duration
                   options:(UIViewAnimationOptions)options
                completion:(void (^)(BOOL finished))completion;

Dinámicas

Pasos:​

  1. Crear un UIDynamicAnimator

  2. Añadir UIDynamicBehaviors (gravedad, colisiones, etc)

  3. Añadir UIDynamicItems (UIViews)

//Create a UIDynamicAnimator
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] 
     initWithReferenceView:aView];
//If animating views, all views must be in a view hierarchy
// with reference view at the top.
//Create and add UIDynamicBehaviors
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] init]; 
[animator addBehavior:gravity];

ICollisionBehavior *collider = [[UICollisionBehavior alloc] init]; 
[animator addBehavior:collider];

UIDynamicItem

Añadir items a behaviors

id <UIDynamicItem> item1 = ...; 
id <UIDynamicItem> item2 = ...; 
[gravity addItem:item1]; 
[collider addItem:item1]; 
[gravity addItem:item2]; 

<UIDynamicItem>
@protocol UIDynamicItem
@property (readonly) CGRect bounds;
@property (readwrite) CGPoint center; 
@property (readwrite) CGAffineTransform transform; 
@end

UIDynamicBehaviour

  • UIGravityBehavior:  ángulo y magnitud

  • UICollisionBehavior: colisiones y límites

  • UIPushBehavior: aceleración en 2 modos [continuous,  instantaneous]

  • UIAttachmentBehavior: alineamiento a un punto u otra vista.

  • UISnapBehavior: animación de estar pegado a un punto.

UIDynamicBehavior superclase para crear una composición

- (void)addChildBehavior:(UIDynamicBehavior *)behavior; 

Autolayout

Definir las UIViews con reglas en vez de números. Muchas restricciones pueden afectar a las vistas:

- Rotación

- Tamaño de la pantalla

- Composición de controles

 

Normalmente se utiliza el XCode para configurarlo

Gestos

UIGestureRecognizer es la clase que reconoce los gestos. Es una clase abstracta, normalmente la implementación está contenida en el UIViewController o en el mismo UIView.

- (void)setPannableView:(UIView *)pannableView 
{
    _pannableView = pannableView;
    UIPanGestureRecognizer *pangr =
      [[UIPanGestureRecognizer alloc] 
      initWithTarget:pannableView //La propia vista como target
      action:@selector(pan:)]; //Método a ejecutar en el target
    [pannableView addGestureRecognizer:pangr]; //Activar el gesto en la vista
}

UIGestureRecognizer

UIPanGestureRecognizer tiene 3 métodos:

- (CGPoint)translationInView:(UIView *)aView;
- (CGPoint)velocityInView:(UIView *)aView;
- (void)setTranslation:(CGPoint)translation inView:(UIView *)aView;

 

Estados:

@property: @property (readonly) UIGestureRecognizerState state;
{Possible, Recognized, 
Began, Failed,

Changed, Ended, Continuous, Cancelled}

Gestos: callback

- (void)pan:(UIPanGestureRecognizer *)recognizer
{
  if ((recognizer.state == UIGestureRecognizerStateChanged) ||
    (recognizer.state == UIGestureRecognizerStateEnded)) {
    CGPoint translation = [recognizer translationInView:self];

    // move something in myself (I’m a UIView) by translation.x and translation.y
    // for example, if I were a graph and my origin was set by an @property called origin 
    self.origin =   CGPointMake(self.origin.x+translation.x, self.origin.y+translation.y);
    [recognizer setTranslation:CGPointZero inView:self]; // Reset cumulative distance
  } 
}

Más gestos

UIPinchGestureRecognizer

@property CGFloat scale;  

@property (readonly) CGFloat velocity; 

UIRotationGestureRecognizer
@property CGFloat rotation;
@property (readonly) CGFloat velocity;

UISwipeGestureRecognizer
@property UISwipeGestureRecognizerDirection direction; @property NSUInteger numberOfTouchesRequired; 

UITapGestureRecognizer
@property NSUInteger numberOfTapsRequired;

@property NSUInteger numberOfTouchesRequired; 

UIScrollView

Dentro del XCode: un UIView se puede embeber en un Scroll View.

UIApplication

 

Objeto aplicación, diferente del Application Delegate que contiene información global.

 

UIApplication *myApplication =

         [UIApplication sharedApplication];

Network Activity Indicator

Propiedad de UIApplication.

@property (nonatomic, getter=is...) networkActivityIndicatorVisible; 

 

Cuando esta propiedad se pone a YES, aparece un spinner en la status bar indicando cuándo hay actividad en la red.

Modal, Text Fields, Alertas y Acciones

Modal View Controller

Se superpone a la pantalla actual, rompiendo la navegación -> Ventana modal.

Transiciones:

@property UIModalTransitionStyle modalTransitionStyle; UIModalTransitionStyleCoverVertical, UIModalTransitionStyleFlipHorizontal. UIModalTransitionStyleCrossDissolve, UIModalTransitionStylePartialCurl 

Pantalla en iPad

@property UIModalPresentationStyle modalPresentationStyle; 

UIModalPresentationFullScreen, UIModalPresentationPageSheet, UIModalPresentationFormSheet, UIModalPresentationCurrentContext

UITextField

UILabel pero editable. Interacción clave con el teclado.

 

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    if (textField == SSN) { // SSN is an outlet
        NSString *regEx = @"[0-9]{3}-[0-9]{2}-[0-9]{4}";
        NSRange r = [textField.text rangeOfString:regEx options:NSRegularExpressionSearch];
        if (r.location == NSNotFound) {
            UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error"
                message:@"Enter social security number in 'NNN-NN-NNNN' format"
                delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
            [av show];
            return NO;
        }
    }
        return YES;
}

Teclado personalizado

@property(nonatomic) UIKeyboardType keyboardType

myTextField.keyboardType = UIKeyboardTypeASCIICapable;

 

UIKeyboardTypeDefault, UIKeyboardTypeASCIICapable, UIKeyboardTypeNumbersAndPunctuation, UIKeyboardTypeURL, UIKeyboardTypeNumberPad, UIKeyboardTypePhonePad, UIKeyboardTypeNamePhonePad, UIKeyboardTypeEmailAddress, UIKeyboardTypeDecimalPad, UIKeyboardTypeTwitter, UIKeyboardTypeWebSearch, UIKeyboardTypeAlphabet = UIKeyboardTypeASCIICapable

Popups: Action sheet

Menú de acciones de estilo iPhone.

Popups: Action sheet

Menú de acciones de estilo iPhone.

-(id)initWithTitle:(NSString *)title
  delegate:(id <UIActionSheetDelegate>)delegate
  cancelButtonTitle:(NSString *)cancelButtonTitle 
  destructiveButtonTitle:(NSString *)destructiveButtonTitle
  otherButtonTitles:(NSString *)otherButtonTitles, ...;

- (void)addButtonWithTitle:(NSString *)buttonTitle;

//Displaying the Action Sheet!
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:...];
[actionSheet showInView:(UIView *)]; // centers the view on iPad 
[actionSheet showFromRect:(CGRect) inView:(UIView *) animated:(BOOL)]; 
[actionSheet showFromBarButtonItem:(UIBarButtonItem *) animated:(BOOL)];

Popups: Alert View

Popups: Alert View

-(id)initWithTitle:(NSString *)title
   message:(NSString *)message
   delegate:(id <UIActionSheetDelegate>)delegate
  cancelButtonTitle:(NSString *)cancelButtonTitle
  otherButtonTitles:(NSString *)otherButtonTitles, ...;



UIAlertView *alert = [[UIAlertView alloc] initWithTitle:...];
[alert show]; 
alert.alertViewStyle = UIAlertViewStyle{SecureText,PlainText,LoginAndPassword}Input; 

Popups: Alert View

UIAlertView *alert = [[[UIAlertView alloc] 
   initWithTitle:@"Username:" 
   message:@"Please enter your username:" 
   delegate:self cancelButtonTitle:@"Cancel" 
   otherButtonTitles:nil] autorelease];
    
    alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
    alert.tag = 12;
    
    [alert addButtonWithTitle:@"Go"];
    [alert show];
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (alertView.tag == 12) {
        if (buttonIndex == 1) {
            UITextField *textfield = [alertView textFieldAtIndex:0];
            NSLog(@"username: %@", textfield.text);
        }
    }
}

Deprecated en iOS 9

UIAlertController * alert=   [UIAlertController
                                 alertControllerWithTitle:@"Title"
                                 message:@"Message"
                                 preferredStyle:UIAlertControllerStyleAlert];

   UIAlertAction* yesButton = [UIAlertAction
                        actionWithTitle:@"Yes, please"
                        style:UIAlertActionStyleDefault
                        handler:^(UIAlertAction * action)
                        {
                            //Handel your yes please button action here
                            [alert dismissViewControllerAnimated:YES completion:nil];

                        }];
   UIAlertAction* noButton = [UIAlertAction
                            actionWithTitle:@"No, thanks"
                           style:UIAlertActionStyleDefault
                           handler:^(UIAlertAction * action)
                           {
                               [alert dismissViewControllerAnimated:YES completion:nil];

                           }];

   [alert addAction:yesButton];
   [alert addAction:noButton];

   [self presentViewController:alert animated:YES completion:nil];

UIAlertView is deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert instead

Popover

UIPopoverController no es un UIViewController, contiene una referencia al controller.

@property (nonatomic, strong) UIViewController *contentViewController; 

- (IBAction)presentPopover:(UIBarButtonItem *)item
{
      if (!self.popover) {
          self.popover = [[UIPopoverController alloc] initWithViewController:vc];
          [self.popover presentPopoverFromBarButtonItem:item ...];
      }
}

- (void)dismissPopoverAnimated:(BOOL)animated; 

también deprecated

UIModalPresentationPopover

avc.modalPresentationStyle = UIModalPresentationPopover;
avc.popoverPresentationController.sourceView = theButton;
[self presentViewController:avc animated:YES completion:nil];

Universal Apps

Universal Applications

Es una única aplicación que corre tanto en iPhone como en iPad.

Se crea un nuevo storyboard para iPad/iPhone

 

BOOL iPad = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);

UISplitViewController

Top-level controller para iPad. Con 2 view controller, master y detail.

 

Networking

Model Framework for Cocoa and Cocoa Touch

Mantle

Permite componer una capa model de abstracción sencilla.

Evitando tener que trabajar con

-hash
-isEqual:
NSCopying
NSCoding

Ejemplo.

Example: Book Model
@interface TGRBook : MTLModel

@property (copy, nonatomic, readonly) NSString *author; 
@property (copy, nonatomic, readonly) NSString *overview; 
@property (copy, nonatomic, readonly) NSArray *genres; 
@property (copy, nonatomic, readonly) NSDate *releaseDate; 
@property (copy, nonatomic, readonly) NSNumber *identifier; 
@property (copy, nonatomic, readonly) NSString *title; 
@property (copy, nonatomic, readonly) NSURL *coverURL;

@end

Ejemplo.

NSError *error = nil;
TGRBook *book = [TGRBook modelWithDictionary:@{
@"title" : @"The Sandman",
@"author" : @"Neil Gaiman",
@"genres" : @[@"Graphic Novels", @"Fantasy"], ...
} error:&error];

TGRBook *anotherBook = [book copy];

[NSKeyedArchiver archiveRootObject:book toFile:@"my_file"];

TGRBook *b = [NSKeyedUnarchiver unarchiveObjectWithFile:@"my_file"];

Simplemente heredando de MTLModel

El modelo puede estar representado en JSON

Our Book Model could have a JSON representation
{
...
"artistName": "Neil Gaiman, Sam Keith & Mike Dringenberg",
 "description": "<p>NEW YORK TIMES bestselling author...",
 "genres": ["Graphic Novels", "Books", "Comics & Graphic Novels"],
 "releaseDate": "2012-08-21T07:00:00Z",
 "trackId": 554016043,
 "trackName": "The Sandman, Vol. 1: Preludes & Nocturnes (New Edition)", "artworkUrl100":   "http://a4.mzstatic.com/us/r30/Publication/...",
...
}
This is how iTunes represents media (including books)

Simplemente heredando de MTLModel

MTLJSONSerializing

@interface TGRBook : MTLModel <MTLJSONSerializing>

 

Hay que especificar:

Cómo mapear las propiedades con el path JSON

Como convertir el valor de JSON a property key.

MTLJSONSerializing

+ (NSDictionary *)JSONKeyPathsByPropertyKey {

return @{

@"author" @"artistName",

 @"overview" @"description",

 @"identifier" @"trackId",

 @"title" @"trackName",

 @"coverURL" @"artworkUrl100" };

}

 

MTLValueTransformer

+<key>JSONTransformer methods

Predefinidos:

MTLURLValueTransformerName MTLBooleanValueTransformerName 

+ (NSValueTransformer *)releaseDateJSONTransformer {
    return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSString *str) {
       return [self.dateFormatter dateFromString:str]; 
    } reverseBlock:^(NSDate *date) {
       return [self.dateFormatter stringFromDate:date]; 
    }];
}

+ (NSValueTransformer *)coverURLJSONTransformer {
   return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
}

Mapping estructuras

@interface TGRUser : MTLModel <MTLJSONSerializing>

 @property (copy, nonatomic, readonly) NSArray *purchasedBooks; 
 @property (copy, nonatomic, readonly) TGRBook *nowReading;

@end

+ (NSValueTransformer *)purchasedBooksJSONTransformer {
    return [NSValueTransformer mtl_JSONArrayTransformerWithModelClass:TGRBook.class];
}

+ (NSValueTransformer *)nowReadingJSONTransformer {
   return [NSValueTransformer mtl_JSONDictionaryTransformerWithModelClass:TGRBook.class];
}

MTLJSONAdapter


TGRBook *book = 
    [MTLJSONAdapter modelOfClass:TGRBook.class
                    fromJSONDictionary:JSONDictionary
                    error:&error];

NSDictionary *dictionary =
     [MTLJSONAdapter JSONDictionaryFromModel:book];

Transformer reversible.

Puede convertir cualquier modelo que implemente <MTLJSONSerializing> en un NSDictionary y viceversa

MTLManaged

// MTLManagedObjectSerializing protocol
// Entity name
+ (NSString *)managedObjectEntityName { 
    return @"Book";
}

// Map
+ (NSDictionary *)managedObjectKeysByPropertyKey { 
    return @{
        @"coverURL" : @"coverLink"
    };
}

// Transformer
+ (NSValueTransformer *)coverURLEntityAttributeTransformer {
return [[NSValueTransformer valueTransformerForName:MTLURLValueTransformerName]
}

//MTLManagedObjectAdapter

NSManagedObject *managedBook = 
    [MTLManagedObjectAdapter managedObjectFromModel:book
    insertingIntoContext:moc];

TGRBook *book = [MTLManagedObjectAdapter modelOfClass:TGRBook.class
        fromManagedObject:object error:&error];

Easy Networking Framework

NSURL *url = [NSURL URLWithString:@"https://itunes.apple.com"]; 

AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:url]; !

[client getPath:@"search" parameters:@{
  @"term" : @"the sandman",
  @"entity" : @"ebook"
 } success:^(AFHTTPRequestOperation *operation, id JSONResponse) {
        NSLog(@"Search results: %@", JSONResponse);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        ...
}];

Respuesta en JSON

{
"resultCount": 50, "results": [{
"artistId": 3603584,
"artistName": "Neil Gaiman, Sam Kieth & Mike Dringenberg",
"kind": "ebook",
"price": 1.99,
"description": "<p>The first issue of the first volume...",
"currency": "USD",
"genres": ["Graphic Novels", "Books", "Comics & Graphic Novels"],
"genreIds": ["10015", "38", "9026"],
"releaseDate": "2013-05-01T07:00:00Z",
"trackId": 642469670,
"trackName": "Sandman #1",
...

+ Mantle

NSURL *url = [NSURL URLWithString:@"https://itunes.apple.com"]; 
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:url]; !

[client getPath:@"search" 
    parameters:@{ 
        @"term" : @"Neil Gaiman",
        @"entity" : @"ebook"
} success:^(AFHTTPRequestOperation *operation, NSDictionary *JSONResponse) {

    NSArray *results = JSONResponse[@"results"];
    NSValueTransformer *transformer;
    transformer = [NSValueTransformer 
        mtl_JSONArrayTransformerWithModelClass:TGRBook.class]; 
    NSArray *books = [transformer transformedValue:results];
    NSLog(@"Books: %@", books);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    ... 
}];

El mapping puede ser costoso, debería hacerse fuera del thread principal de la UI

NSNotification

NSNotification

Notificaciones de eventos del MVC

[NSNotificationCenter defaultCenter]

Registrarse a eventos:

- (void)addObserver:(id)observer selector:(SEL)methodToInvokeIfSomethingHappens

    name:(NSString *)name // name of station (a constant somewhere)

   object:(id)sender; // whose changes you’re interested in (nil is anyone’s)

Notificación del evento:

- (void)methodToInvokeIfSomethingHappens:(NSNotification *)notification {
notification.name // the name passed above
notification.object // the object sending you the notification

notification.userInfo // notification-specific information about what happened

Lista de notificaciones del sistema

// System/Library/Frameworks/UIKit.framework/Headers/UIApplication.h
UIKIT_EXTERN NSString *const UIApplicationDidEnterBackgroundNotification       NS_AVAILABLE_IOS(4_0);
UIKIT_EXTERN NSString *const UIApplicationWillEnterForegroundNotification      NS_AVAILABLE_IOS(4_0);
UIKIT_EXTERN NSString *const UIApplicationDidFinishLaunchingNotification;
UIKIT_EXTERN NSString *const UIApplicationDidBecomeActiveNotification;
UIKIT_EXTERN NSString *const UIApplicationWillResignActiveNotification;

Push Notification

Push Notification

Push Notification - Message

{
	"aps":
	{
		"alert":
		{
			"action-loc-key": "Open",
			"body": "Hello, world!"
		},
		"badge": 2
	}
}

Multithreading

Multithreading

"Asynchronous design approach"

Mecanismo basado en colas, donde se acumulan los bloques a ejecutar, que luego se ejecutan en el thread asociado

 

La cola principal es la que maneja la UI. Toda actividad en la UI debe realizarse en la cola principal. Actividad no relacionada con la UI que consuma mucho tiempo debería realizarse sin bloquear la cola principal.

Multithreading

Obtener la referencia a la cola principal

NSOperationQueue *mainQ = [NSOperationQueue mainQueue];

 

Ejecutar una acción en la cola principal.

NSObject method

  - (void)performSelectorOnMainThread:(SEL)aMethod
             withObject:(id)obj

             waitUntilDone:(BOOL)waitUntilDone; 

Ejemplo de API asíncrona

NSURLRequest *request = [NSURLRequest requestWithURL:
       [NSURL urlWithString:@“http://...”]];
NSURLConfiguration *configuration = ...;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
             delegate:nil
             delegateQueue:[NSOperationQueue mainQueue]];
  NSURLSessionDownloadTask *task;
  task = [session downloadTaskWithRequest:request
                        completionHandler:^(NSURL *localfile, 
                        NSURLResponse *response, NSError *error) {
/* UI tasks on mainQueue delegate */ }];
[task resume];

Ejemplo de API asíncrona

NSURLRequest *request = [NSURLRequest requestWithURL:
       [NSURL urlWithString:@“http://...”]];
NSURLConfiguration *configuration = ...;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
// No delegateQueue
  
NSURLSessionDownloadTask *task;
task = [session downloadTaskWithRequest:request
        completionHandler:^(NSURL *localfile, 
        NSURLResponse *response, NSError *error) {
/* Non UI tasks */ 

/* Now UI tasks on main queue */
[self performSelectorOnMainThread:@selector(doUIthings)
    withObject:nil waitUntilDone:NO];

}];
[task resume];

Biblioteca para la ejecución de código concurrente, on iOS y OSX multicore.

 

Proporciona colas thread-safe:

serial queues -> colas de ejecución de una tarea cada vez (FIFO)

concurrent queues -> comienzan FIFO, pero acaban sin garantía

 

Grand Central Dispatch

Background task

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
    NSURL *url = [NSURL URLWithString:myURL];
    myData = [NSData dataWithContentsOfURL:url];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self processTheData:myData];
    });
});

// UI Update
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
    NSURL *url = [NSURL URLWithString:myURL];
    myData = [NSData dataWithContentsOfURL:url];
    [self processTheData:myData];

    dispatch_async(dispatch_get_main_queue(), ^{
        // code that updates UI goes here
    });

});

Limitar las operaciones con NSOperationQueue



@property (nonatomic, strong) NSOperationQueue *queue;
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.queue = [[NSOperationQueue alloc] init];
    self.queue.maxConcurrentOperationCount = 4;
}

[self.queue addOperationWithBlock:^{
    NSURL *url = [NSURL URLWithString:myURL];
    myData = [NSData dataWithContentsOfURL:url];
    [self processTheData:myData];
    [[NSOperationQueue mainQueue] addOperationWithBlock:{
        // code that updates UI goes here
    }];
}]; 

Delays - dispatch_after

- (void)showOrHideNavPrompt
{
    NSUInteger count = [[PhotoManager sharedManager] photos].count;
    double delayInSeconds = 1.0;
    dispatch_time_t popTime = 
        dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); // 1 
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // 2 
        if (!count) {
            [self.navigationItem setPrompt:@"Add photos with faces to Googlyify them!"];
        } else {
            [self.navigationItem setPrompt:nil];
        }
    });
}

Locks - dispatch_once

+ (instancetype)sharedManager
{
    static PhotoManager *sharedPhotoManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedPhotoManager = [[PhotoManager alloc] init];
        sharedPhotoManager->_photosArray = [NSMutableArray array];
    });
    return sharedPhotoManager;
}

Permite hacer un singleton thread-safe

NSURL* url = [NSURL URLWithString:@"http://example.com"];
NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest addValue:@"application/json" forHTTPHeaderField:@"Accept"];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:urlRequest
                                   queue:queue
                       completionHandler:^(NSURLResponse* response,
                                           NSData* data,
                                           NSError* error)
{
    if (data) {
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
        // check status code and possibly MIME type (which shall start with "application/json"):
        NSRange range = [response.MIMEType rangeOfString:@"application/json"];

        if (httpResponse.statusCode == 200 /* OK */ && range.length != 0) {
            NSError* error;
            id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
            if (jsonObject) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    // self.model = jsonObject;
                    NSLog(@"jsonObject: %@", jsonObject);
                });
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    //[self handleError:error];
                    NSLog(@"ERROR: %@", error);
                });
            }
        }
        else {
            // status code indicates error, or didn't receive type of data requested
            NSString* desc = [[NSString alloc] initWithFormat:@"HTTP Request failed with status code: %d (%@)",
                              (int)(httpResponse.statusCode),
                              [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]];
            NSError* error = [NSError errorWithDomain:@"HTTP Request"
                                                 code:-1000
                                             userInfo:@{NSLocalizedDescriptionKey: desc}];
            dispatch_async(dispatch_get_main_queue(), ^{
                //[self handleError:error];  // execute on main thread!
                NSLog(@"ERROR: %@", error);
            });
        }
    }
    else {
        // request failed - error contains info about the failure
        dispatch_async(dispatch_get_main_queue(), ^{
            //[self handleError:error]; // execute on main thread!
            NSLog(@"ERROR: %@", error);
        });
    }
}];

Core Motion

Sensores

API para acceder a los sensores del dispositivo

  • acelerómetro
  • giróscopo
  • magnetómetro

Mediante la clase CMMotionManager. Acceso a un recurso global, por lo que es recomendable obtener sólo una instancia por aplicación para mantener el rendimiento.

 

Sensores

Primero hay que obtener la disponibilidad del hardware

@property (readonly) BOOL {accelerometer, gyro, magnetometer, deviceMotion}Available

 

Programar los sensores para obtener los datos

-(void)start {Accelerometer,Gyro,Magnetometer,DeviceMotion}Updates; 

@property (readonly) BOOL {accelerometer,gyro,magnetometer,deviceMotion}Active; 

- (void)stop{Accelerometer,Gyro,Magnetometer,DeviceMotion}Updates; 

Sensores

Registrarse para recibir datos de acelerómetro:

- (void)startAccelerometerUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMAccelerometerHandler)handler;

queue == [[NSOperationQueue alloc] init]

Recibir datos de giróscopo: 

- (void)startGyroUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMGyroHandler)handler;

Registrarse al campo magnético

- (void)startMagnetometerUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMMagnetometerHandler)handler;

typedef void (^CMMagnetometerHandler)(CMMagnetometerData *data, NSError *error) 

Localization

Internacionalización - i18n

Registrar los idiomas. Los storyboards extraerán ficheros .strings para cada idioma.

Para strings en el código, utilizar genstrings *-m

NSString *NSLocalizedStringWithDefaultValue(NSString *key, NSString *table,

NSString *bundle, NSString *defaultValue,

NSString *comment); 

Ejemplo: @“hello” -> NSLocalizedString(@“hello”, @“Greeting at start of application.”)

Bundles

Los recursos están contenidos en un bundle para cada idioma (es.lproj).

Dentro de estos directorios estarán los .string, imágenes, sonidos. Primero se busca el idioma top-level (default) y luego el locale específico.

 

NSBundle *bundle = [NSBundle bundleForClass:[self class]];

NSString *path = [bundle pathForResource:@“speedlimit” 

       ofType:@“jpg”];

Locale

NSLocale es diferente para cada idioma. Indica el idioma seleccionado por el usuario en los ajustes.

De esta manera, se pueden ajustar fechas y números según el idioma.

+ (NSString *)localizedStringFromNumber:(NSNumber *)number

numberStyle:(NSNumberFormatterStyle)style

 

NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];

[formatter setNumberStyle:NSNumberFormatterDecimalStyle];

NSNumber *parsedNumber = [formatter numberFromString:userInputtedString]; 

 

Ajustes

Ajustes

NSUserDefaults

Getter

 

if ([[NSUserDefaults standardUserDefaults] boolForKey:@"CacheDataAggressively"]) {

   // Do something

}

 

Setter

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

 

   [defaults setBool:YES forKey:@"CacheDataAggressively"];

   [defaults setObject:[NSDate dateWithTimeIntervalSinceNow:(3600 * 24 * 7)]

             forKey:@"CacheExpirationDate"]; // Set a 1-week expiration

 

Geolocalización

Core Location

Es un framework para manejar localización y direcciones, no tiene UI

 

CLLocation
@propertyscoordinatealtitudehorizontal/verticalAccuracytimestampspeedcourse

Core Location

@property (readonly) CLLocationCoordinate2D coordinate;
 typedef {
CLLocationDegrees latitude; // a double
CLLocationDegreeslongitude; //adouble } CLLocationCoordinate2D;
}

@property (readonly) CLLocationDistance altitude; // meters A negative value means “below sea level.”

@property (readonly) CLLocationAccuracy horizontalAccuracy; // in meters 
@property (readonly) CLLocationAccuracy verticalAccuracy; // in meters 

kCLLocationAccuracyBestForNavigation
kCLLocationAccuracyBest
kCLLocationAccuracyNearestTenMeters
kCLLocationAccuracyHundredMeters
kCLLocationAccuracyKilometer
kCLLocationAccuracyThreeKilometers

Dirección y velocidad


 @property (readonly) CLLocationDirection course;

 @property (readonly) NSDate *timestamp;

// in degrees, 0 is north, clockwise 
@property (readonly) CLLocationSpeed speed; // in meters/second 

Distance between CLLocations
- (CLLocationDistance)distanceFromLocation:(CLLocation *)otherLocation; // in meters

CLLocationManager



+ (CLAuthorizationStatus)authorizationStatus; // Authorized, Denied or Restricted (parental, enterprise)

+ (BOOL)locationServicesEnabled; // user has enabled (or not) location services for your application

+ (BOOL)significantLocationChangeMonitoringAvailable; 

+ (BOOL)isMonitoringAvailableForClass:(Class)regionClass; //[CLBeacon/CLCircularRegionclass] 

+ (BOOL)isRangingAvailable; // device can tell how far it is from beacons!
  •  Crear una instancia de CLLocationManager y configurar un delegado para notificaciones push
  • Configurar el tipo de localización deseada y monitorizar (pull)
     

Push



// Error reporting
 - (void)locationManager:(CLLocationManager *)manager
        didFailWithError:(NSError *)error;
kCLErrorLocationUnknown
kCLErrorDenied
kCLErrorHeadingFailure

@property CLLocationAccuracy desiredAccuracy; 
@property CLLocationDistance distanceFilter; !

- (void)startUpdatingLocation;
- (void)stopUpdatingLocation;
// Recomendable asegurarse de pararlo si no se van a procesar.

//Notificación
(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations; // of CLLocation! 

- (void)startMonitoringSignificantLocationChanges;
- (void)stopMonitoringSignificantLocationChanges;

Beacons

 

CLLocationManager

- (void)startMonitoringForRegion:(CLRegion *)region;

// CLCircularRegion/CLBeaconRegion

- (void)stopMonitoringForRegion:(CLRegion *)region;
 

Detectando cuándo se entra en una región o cerca de otro dispositivo

Beacons

CLLocationManager’s delegate

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;

- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region

withError:(NSError *)error;

 

Ejemplo

UPM Example

App, Icons, Splash

git checkout splash

  1. Creamos la aplicación como Single View
  2. Modificamos el icono
    1. Ejemplo
  3. Modificamos el Splash
    1. Ejemplo
  4. Podemos crear todos los iconos necesarios en http://makeappicon.com
  5. Se añaden en los assets

Login

git checkout splash

  1. Pantalla de Login
  2. Campos de texto: 
    1. user
    2. password
    3. IBOutlet
  3. Botón de entrar 
    1. Segue
    2. IBAction
    3. Alert View

Pantalla de alumno

git checkout alumno

  1. Foto del alumno
  2. Campos de texto: 
    1. name
    2. email
  3. Navigation Bar
  4. Navigation Bar Item
  5. Edit segue

Editar alumno

git checkout editar_alumno

  1. Foto del alumno
    1. UIImagePickerController
  2. Campos de texto: 
    1. name
    2. email
  3. Navigation Bar
    1. Navigation Bar Item: Guardar
    2. Navigation Bar Back
  4. Unwind segue

UIImagePickerController

Vista model para obtener referencias a las fotos y vídeos de la cámara y la galería. 

Primero hay que probar qué capacidades hay disponibles:

+ (BOOL)isSourceTypeAvailable:(UIImagePickerControllerSourceType) sourceType;

UIImagePickerControllerSourceTypePhotoLibrary/Camera/SavedPhotosAlbum

 

+ (BOOL)isCameraDeviceAvailable:(UIImagePickerControllerCameraDevice) cameraDevice;
UIImagePickerControllerCameraDeviceFront| UIImagePickerControllerCameraDeviceRear

UIImagePickerController

- (IBAction)takePhoto:(UIButton *)sender {
 UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.allowsEditing = YES;
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    [self presentViewController:picker animated:YES completion:NULL];
}

- (void)imagePickerController:(UIImagePickerController *)picker 
  didFinishPickingMediaWithInfo:(NSDictionary *)info
{
  // extract image/movie data/metadata here, more on the next slide
  UIImage *chosenImage = info[UIImagePickerControllerEditedImage];

  [self dismissViewControllerAnimated:YES completion:...]; // or popover dismissal 
}

// Also dismiss it when cancel happens!
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
  [self dismissViewControllerAnimated:YES completion:...]; // or popover dismissal
}

Tab Bar

git checkout editar_alumno

  1. Creamos el TabBarController
  2. Tab Bar Items
    1. Iconos
    2. Títulos
    3. Enlaces

Table View

git checkout expediente

  1. Table View Controller
  2. Configuramos la celda
  3. Creamos el modelo estático

Web View

git checkout ayuda

  1. Creamos un nuevo Tab Bar item
  2. Añadimos un WebView
  3. Cargamos el HTML desde el mismo bundle.

git checkout settings

  1. Nuevo Settings Bundle
  2. Modificamos las propiedades.

Avisos - Pager

git checkout avisos

  1. UIPageViewController
  2. Modelo estático de avisos
  3. Modelo de página

Login - request

git checkout login_network

  1. Mantle + AFNNetworking
  2. JSON
  3. Ojo con el segue!

Expediente - request

git checkout login_network

  1. Mantle + AFNNetworking
  2. Modelo
  3. JSON array
  4. TableViewCell