viernes, 30 de diciembre de 2011

Obtener una subcadena de un objeto String

NSString *str = @"Hola Mundo";
NSString *newStr = [str substringWithRange:NSMakeRange(0,4)];
newStr sería igual a "Hola".

miércoles, 28 de diciembre de 2011

Evitar que el teclado quede sobre los textfields

Uno de los problemas más comunes cuando programamos para iphone es que el teclado puede ocultar los textfields. La solución más rápida es correr los textfields de manera que no queden ocultos pero en mi aplicación yo tenía varios textfields y no me quedaba lugar para correrlos.

Encontré este tutorial http://joshhighland.com/blog/2010/04/20/iphone-keyboard-covers-text-field/ que me pareció que es el que tiene el código más simple y me funciono perfecto.
 
La idea es la siguiente, realizar dos IBAction en este caso slideFrameUp y slideFrameDown que seran llamados por los textfields cuando ocurran los enventos Editing Did Begin y Editing Did End respectivamente (como se muestra en la figura).


El código de los IBAction y del método que llaman los mismos es el siguiente:

-(IBAction) slideFrameUp;
{
    [self slideFrame:YES];
}
 
-(IBAction) slideFrameDown;
{
    [self slideFrame:NO];
}
 
-(void) slideFrame:(BOOL) up
{
    const int movementDistance = 50; // lo que sea necesario, en mi caso yo use 80
    const float movementDuration = 0.3f; // lo que sea necesario
 
    int movement = (up ? -movementDistance : movementDistance);
 
    [UIView beginAnimations: @"anim" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

miércoles, 14 de diciembre de 2011

Mostrar una imagen desde una url



NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: @"http://myurl/mypic.jpg"]];
cell.image = [UIImage imageWithData: imageData];
[imageData release];


lunes, 5 de diciembre de 2011

¿Cómo convierto un int a un NSString?


Una de las formas es mediante un método de NSString
[NSString stringWithFormat:@”%i” , elentero]

¿Y de NSString a float o a int?
La clase NSString tiene métodos para esto uno es floatValue y el otro intValue.
 NSString *aNumberString = @"35";
 int i = [aNumberString intValue];

Imágenes con bordes redondeados

Cada objeto basado en una vista tiene asociado una capa y cada capa tiene un corner al que se le puede setear su radio. Por lo tanto lo que podemos hacer es lo siguiente: No hay que olvidar que debemos importar el siguiente framework
imageView.layer.cornerRadius = 5.0;
imageView.layer.masksToBounds = YES;

//para agregar un borde:

imageView.layer.borderColor = [UIColor lightGrayColor].CGColor;
imageView.layer.borderWidth = 1.0;

lunes, 7 de noviembre de 2011

iOS 5 - ¿Cómo instalar otros simuladores en XCode 4.2?

Desde el menú de Xcode nos vamos a XCode > Preferences > Downloads y desde ahí podemos seleccionar el simulador  iOS 4.3, iOS 4.0 o iOS 3.0.

domingo, 6 de noviembre de 2011

Parte 3: Objective-C. Traducción de la lección 3

Link a la traducción de la lección 3 !!
Lección 3 corregida!!!
pdf en español


pdf en ingles

miércoles, 2 de noviembre de 2011

Como crear una pantalla Splash

La imagen splash es aquella que se muestra al iniciar la aplicación. Simplemente hay que crear una imagen de 320x480 px y llamarla default.png. Luego hay que incluirla en el proyecto, en la raiz o en la carpeta Resources (recordemos que las carpetas creadas en el proyecto son virtuales) y XCode la tomará como la imagen splash que va aparecer antes de que comience la aplicación.

miércoles, 12 de octubre de 2011

Tips Xcode 4

Cambiar entre proyectos abiertos
cmd + `

Agregar un Framework 
  1. En el navegador de proyecto (“project navigator”), selecciona tu proyecto.
  2. Selecciona el objetivo (“target”)
  3. Selecciona la pestaña “Build Phases”.
  4. Abre la sección “Link binaries with libraries”
  5. Haz clic en el botón “+”
  6. Selecciona tu framework
  7. Arrastra la framework  que acaba de añadirse a tu proyecto al grupo de “Frameworks” (opcional).


Para intercambiar entre el  .h y el .m
opt + cmd + flecha hacia arriba

Obtener número del celular
  NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Preferences/.GlobalPreferences.plist"];
    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
    NSLog(@"%@", [dict objectForKey:@"SBFormattedPhoneNumber"]);

jueves, 6 de octubre de 2011

Adaptar el teclado para que solo se ingresen decimales

myTextField.keyboardType=UIKeyboardTypeDecimalPad;

¿Cómo evitar un valor null que obtenemos de json?

[aTweet objectForKey:@"starsHotel"] != [NSNull null]

domingo, 4 de septiembre de 2011

Parte 2: Interface Builder y Xcode. Traducción de la lección 2

De vuelta otra vez!! Les dejo el link al pdf traducido de la lección 2.
pdf en español


pdf en ingles

jueves, 4 de agosto de 2011

Ejemplo de como obtener información de un .plist

En este caso necesitaba obtener información de un .plist para verla en un textField al iniciar la aplicación para eso en el método viewDidLoad de mi viewController agregue este código:
    

- (void)viewDidLoad {

    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSString *finalPath = [path stringByAppendingPathComponent:@"Info.plist"];
    NSDictionary *plistData = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain];
   
    NSString *asa =  [plistData objectForKey:@"AsaPapel"];
    //asaE es el textField
    asaE.text = asa; 
}

martes, 2 de agosto de 2011

NSLog - Especificadores de formato


%@     Objecto
%d, %i signed int
%u     unsigned int
%f     float/double

%x, %X hexadecimal int
%o     octal int
%zu    size_t
%p     puntero
%e     float/double (en notación científica)
%g     float/double ( %f o %e, dependiendo del valor)
%s     C string (bytes)
%S     C string (unichar)
%.*s   Pascal string (requiere dos argumentos, pstr[0] el primero, pstr+1 el segundo)
%c     character
%C     unichar

%lld   long long
%llu   unsigned long long
%Lf    long double

domingo, 29 de mayo de 2011

Objective-C - Punteros

La memoria en la computadora puede ser imaginada como una serie de casillas de correo, cada una con el menor tamaño que usa una computadora (un byte).
Estas casillas de correo se enumeran secuncialmente, entonces para obtener la dirección siguiente agregamos un 1 a la dirección actual.
Por ejemplo, tomemos la siguiente declaración:
int anInteger = 42;
Asumimos que anInteger (con el valor 42) es alojado en la dirección de memoria 32, en otras palabras la dirección de memoria 32 que se llama anInteger contiene el valor 42.
Las direcciones de memoria pueden contener distintos tipos de valores, un int, un float o un puntero que es una dirección de memoria.

Ahora veamos esta declaración:
int *anIntPointer = &anInteger
La primera parte de la declaración declara una variable llamada anIntPointer.
El * le dice al compilador que este tipo es un puntero a un entero en vez de un entero. La referencia & le dice al compilador que quiere que anIntPointer se inicialice con la dirección de anInteger, que es la variable que declaramos antes.

En otras palabras, anIntPointer tendra la dirección de memoria de anInteger, por lo tanto anIntPointer tendra guardado el valor 32.
Para ir desde el puntero anIntPointer que contiene la dirección de anInteger al valor actual de anInteger utilizamos el operador (*).



por ejemplo, el resultado del siguiente código
int anInteger = 42;
    int *anIntPointer = &anInteger;
    NSLog (@”anInteger = %i”, anInteger);
    NSLog (@”*anIntPointer = %i”, *anIntPointer);
    
es

anInteger = 42
*anIntPointer = 42

jueves, 5 de mayo de 2011

¿Cómo programar C con XCode?

Seleccionamos File > New > New Project, luego elegimos "Command Line Utility" y seleccionamos C.
En el proyecto vamos a ver que tenemos creado un archivo llamado main.c para escribir nuestro código.
Eso es todo!

viernes, 29 de abril de 2011

Objective-C - Clase NSNumber

Los números se pueden trabajar con NSNumber.
NSNumber tiene métodos de clase para crear NSNumbers de distintos tipos, por ejemplo:

+ numberWithBool:


Una vez creado el número podemos acceder a el de manera de que nos devuelva diferentes tipos.
También hay métodos para comparar:

– compare:
– isEqualToNumber:

En que caso uso NSNumber y en cuales NSInteger?
No hay regla, es depende de lo que quieres hacer.
A diferencia de NSNumber, NSInteger no es un objeto, es un macro.
Se debe usar NSNumber si o si (de lo contrario la aplicación nos dara error) cuando se quiere insertar objetos a un array.

sábado, 5 de marzo de 2011

Objective-C - Introspección

Introspección significa determinar en tiempo de ejecución la estructura de un objeto.
En Objective-C podemos realizar la introspección mediante 3 métodos:


isKindOfClass: si un objeto es ese tipo de clase (incluye herencia)
isMemberOfClass: si un objeto es ese tipo de clase (sin herencia)
respondsToSelector: si un objetore responde a un método determinado

martes, 1 de marzo de 2011

Comparar dos cadenas NSString

if ([cadena1 isEqualToString: cadena2])
{
// Codigo
}

viernes, 18 de febrero de 2011

Conceptos Fundamentales - Categorías y Extensiones

Categorías

Una categoría permite añadir nuevos métodos a clases ya existentes sin crear subclases. Lo que no se puede es agregar variables de instancia para esa clase.
Para una categoría tenemos dos archivos que son los mismos que para una clase, la interfaz que consiste en un archivo .h y la implementación que consiste en el archivo .m .

La diferencia que existe con una clase es que, las categorías:
1 - Tienen un nombre de una clase ya existente como por ej NSObject
2 - En la interfaz no indicamos de quien heredamos
3 - En la intefaz como en la implementación el nombre de la categoría va entre paréntesis

No se puede usar @sintetize
El nombre del archivo de una categoría es el de la clase seguido de la categoría.

Las categorías son muy útiles cuando se quiere agregar funcionalidad a una clase, pero no queremos reescribirla o no contamos con el código fuente el código fuente de la clase como cuando esta se encuentra en una biblioteca.

Por ejemplo:

Supongamos que tenemos la clase Perro y agregamos la categoría PerroTrucos
//  Perro.h
@interface Perro : NSObject{
}
-(void) ladra;
@end


//  Perro.m
#import "Perro.h"
@implementation Perro
-(void) ladra {
        //Guau guau
}
@end


//  PerroTrucos.h
@interface Perro (Trucos) {
}
-(void) traeLaVarita;
@end


//  Perro.m
#import "PerroTrucos.h"
@implementation Perro (Trucos)
-(void) traeLaVarita {
 //va por la varita
}
@end

Para crear una categoría, se debe declarar con @interface NombreDeClaseExistente (NombreDeCategoriaNueva)
Una vez declarada la categoría se define con @implementation NombreDeClaseExistente (NombreDeCategoriaNueva)

Extensiones
La extensión es un caso especial de categoría a la cual no se le da un nombre entre parentesis, es anonima.
Sus métodos se implementan en la implementación principal de nuestra clase para que puedan definir metodos privados.

jueves, 17 de febrero de 2011

Parte 2 - Tarea 1. Ejemplo aplicación iphone (Calculadora)

Objetivos

1) Bajar e instalar el iOS4 SDK. (esto pueden hacerlo desde  http://developer.apple.com/devcenter/ios/index.action )
2) Crear un nuevo proyecto con Xcode.
3) Definir un modelo, vista y controlador y conectarlos.
4) Usar Interface Builder para crear la interfaz gráfica


Parte 1  

Crear un nuevo proyecto en Xcode

1. Abrimos /Developer/Applications/Xcode
2. En la pantalla que aparece seleccionamos create a new Xcode project



También se puede crear un nuevo proyecto seleccionando New Proyect desde el menú.



3. En el dialogo que aparece hacemos click sobre View based Application



4. En la pantalla que se presenta hacemos lo siguiente:
  • Navegamos hasta el lugar donde queremos mantener los proyectos para este curso
  • En el campo Save as le ponemos el nombre Calculator


    5. hacemos click en Save.



    Ahora podemos ejecutar la aplicación aunque aparecerá la pantalla del simulador del iphone en blanco. Si todo esto funciona bien entonces el SDK se ha instalado correctamente :).

    6. Volvemos a Xcode y podemos ver que hay un arbol de carpetas llamados Grupos y Archivos (Groups & Files). En este lugar es donde serán administrados todos los archivos.




    En la sección Classes se crean automaticamente los archivos .h y .m para las dos clases  CalculatorAppDelegate y CalculatorViewController. Por ahora no hay que preocuparse por CalculatorAppDelegate.

    Parte 2
    Crear una nueva clase para nuestro modelo

    7. Para crear una nueva clase hacemos click en Groups & Files y seleccionamos New File ... desde el  menú.


    8. Hacemos click sobre Objective class (Subclase de NSObject) y después en el botón siguiente. Todos los objectos en Objective-C son subclases de NSObject.

    9. Xcode preguntará por el nombre de la clase. Escribimos CalculatorBrain.m y dejamos chequeado la opción “CalculatorBrain.h” (Also create “CalculatorBrain.h” ) porque queremos ambos archivos, el de cabecera  (.h) y el de implementación (.m) para nuestra clase CalculatorBrain class.
    Nuestro Modelo ya ha sido creado. Vamos a dejar de lado el modelo y volvemos al controlador para escribir algunas declaraciones para las conexiones que necesitamos hacer entre la vista y el controlador.

    Parte 3
    Definir las conexiones desde/hasta el controlador

    Ahora que ya existen las clases de nuestro modelo hay que implementar nuestro controlador.
    Comencemos definiendolo.

    10. Hacer click en CalculatorViewController.h.

    Vamos a ver una pantalla como la siguiente:



    Notar que Xcode ha puesto el #import de la UIKit  que necesitamos y ha hecho que
    CalculatorViewController sea una subclase de UIViewController. Los Controladores son siempre directa o indirectamente subclases de UIViewController.

    Nuestro archivo de cabecera todavía necesita que definamos lo siguiente:
        a. outlets (variables de instancia en nuestro controlador que apuntan a objetos en nuestra vista)
        b. actions (métodos en nuestro controlador que van a ser enviados desde la vista)
        c. Una variable de instancia en nuestro controlador que apunta a nuestro modelo

    11. Vamos a agregar el outlet que permite que nuestra CalculatorViewController hable con UILabel que representa el display en la vista. LLamaremos display a ese outlet.

    @interface CalculatorViewController : UIViewController {
        IBOutlet UILabel *display;
    }
    @end
    
    

    Notar que la palabra clave IBOutlet no hace nada excepto identificar los oulets.


    12. Ahora agregaremos una variable de instancia llamada brain que apunta desde nuestro Controlador hasta nuestro modelo CalculatorBrain. Necesitamos agregar un  #import a CalculatorViewController.h para encontrar la declaración de CalculatorBrain.

    #import <UIKit/UIKit.h>
    #import "CalculatorBrain.h"
    @interface CalculatorViewController : UIViewController {
        IBOutlet UILabel *display;
        CalculatorBrain *brain;
    }
    @end
    
    13. Y finalmente vamos a agregar dos acciones que la vista va a enviar  cuando se presionen los botones.

    @interface CalculatorViewController : UIViewController {
        IBOutlet UILabel *display;
        CalculatorBrain *brain;
    }
    - (IBAction)digitPressed:(UIButton *)sender;
    - (IBAction)operationPressed:(UIButton *)sender;
    @end
    
    
    El único argumento de cada método es un objeto UIButton (el objeto le envia el mensaje a nuestro controlador cuando hace click sobre el mismo).



    14. Compilamos y ejecutamos nuevamente la aplicación para saber si hay algún error. Seguramente hay advertencias porque los métodos no están implementados pero no hay problema con esto ya que son solo advertencias. Si aparece algún error se vera el circulo rojo como se ve en la imagen siguiente:



    haciendo click sobre el error se muestra más información sobre el mismo.


    Ahora utilizaremos la herramienta gráfica para agregar un display algunos botones.


    Parte 4

    Crear la Vista con el Interface Builder

    No necesitamos escribir código sino que solo utilizaremos la herramienta Interface Builder. Cuando creamos un proyecto View-base Xcode automaticamente se crea un template . Este template se llama CalculatorViewController.xib (también denominado archivo nib, algunos lo llaman archivo zib ).

    15. Abrir CalculatorViewController.xib.

    16. Interface Builder tiene tres ventanas principales que contienen objetos o grupos de objetos. Es recomendable seleccionar Hide Others para ver que sucede en el Interface Builder.



    La pantalla principal en el Interface Builder muestra todos los objetos de tu archivo .xib:



    El controlador CalculatorViewController es el File’s Owner . Por ahora ignoremos el objeto First Responder. El objeto View es la vista de más alto nivel, es la supervista de todas las vistas que tendremos en la interface. Todos los objetos UIView tienen una jerarquía en la cual cada uno tiene una superview y subviews. Otra de las ventanas es la librería que contiene todos los elementos necesarios para construir la vista. Por ahora vamos a usar dos UIButton and UILabel.


    Otra de las ventanas es el inspector. El contenido de esta ventana cambia dependiendo que objeto este seleccionado. 

    17. Si hacemos  click  en File’s Owner en la pantalla principal, se debería ver esta pantalla:



    La clase de tu File’s Owner debe ser CalculatorViewController. Lo próximo a realizar es poner algo en la pantalla de esta manera:


    18. Comencemos con el dígito 7, localizamos en nuestra librería un botón Round Rect y simplemente lo arrastramos a la vista.


    19. Modificamos el botón para que tenga 64 pixels de ancho. 

    20. La parte más importante es unir el botón con el CalculatorViewController (el File’s Owner en la pantalla principal) que es quien va a enviar el mensaje digitPressed: cuando hagan click sobre el botón. Para esto hay que hacer click en Ctrl y arrastrar una linea desde el botón hasta el Files Owner.


    A medida que te acercas al File’s Owner, debe rodearlo una caja azul, cuando soltas el mouse debe aparecer una ventanita, selecciono en ella el metodo digitPressed: 


    22. Y ahora que ya tenemos hecha la conexión copiamos y pegamos los botones, todos ellos enviaran digitPressed.

    23. Haciendo doble click sobre cada botón se le puede cambiar el nombre. 

    Ahora vamos a hacer las operaciones de los botones:
    24. Arrastramos a la pantalla un botón.

    25. Mantenga presionado Ctrl y arrastro una lines desde este nuevo boton hasta File’s Owner. Nuevamente va a aparecer la ventanita negra pero en este caso la operación va  a ser operationPressed:.

    26. Copiamos esto 5 veces (necesitaremos * / + - = y sqrt) 
    La interfaz debería verse de esta manera:



    27. Arrastramos una etiqueta (UILabel) desde la librería, hacemos doble click y escribimos 0.

    28. Seleccionamos la etiqueta.

    29. Podes modificar las propiedades de los objetos como quieras como se ve en la siguiente imagen:


    El CalculatorViewController necesita enviar mensajes al outlet para actualizarlo.

    31. Arrastramos desde el File’s Owner to the UILabel.


    32. Cuando soltamos el mouse debe aparecer la siguiente ventana. Selecciona display.


    33. Guardamos el archivo de la Interface Builder y luego vuelvemos al Xcode.

    34. Ejecutamos la aplicación.

    Parte 5
    Implementar el Modelo

    El próximo paso es implementar el modelo CalculatorBrain.

    35. Hacemos click en CalculatorBrain.h en la sección  Groups & Files.


    36. Primero nuestro modelo necesita un operando. Será un puntero flotante, entonces hagamos una variable de instancia que sea double.


    double operand;
    

    37. Ahora agreguemos un método que nos permita setear un operando.

    - (void)setOperand:(double)aDouble; 
    

    38. Y finalmente un método que nos permita realizar una operación.

    @interface CalculatorBrain : NSObject {
      double operand;
    }
    - (void)setOperand:(double)aDouble;
    - (double)performOperation:(NSString *)operation;
    @end
    
    

    39. Copiar la declaración de los dos métodos en CalculatorBrain.h, luego cambiar a CalculatorBrain.m  y pegarlo entre @implementation y @end.

    //
    // CalculatorBrain.m
    // Calculator
    //
    // Copyright Stanford CS193p. All rights reserved.
    #import "CalculatorBrain.h"
    @implementation CalculatorBrain
    - (void)setOperand:(double)aDouble;
    - (double)performOperation:(NSString *)operation;
    @end
    
    
    @implementation CalculatorBrain
    - (void)setOperand:(double)aDouble
    {}
    - (double)performOperation:(NSString *)operation
    {}
    @end
    
    

    40. La implementación de setOperand: es facil. Lo que hacemos es darle el valor que viene como argumento a la variable de instancia.

    - (void)setOperand:(double)aDouble
    {
        operand = aDouble;
    }
    
    

    41. La implementación de  performOperation: también es simlple si el operando lo es, como por ej sqrt.

    - (double)performOperation:(NSString *)operation
    {
        if ([operation isEqual:@"sqrt"])
        {
           operand = sqrt(operand);
        }
    
    return operand;
    }
    


    El envío de mensajes a los objetos se hace entre corchetes. En este caso el mensaje es isEqual:.
    Pensemos en operaciones con 2 operandos. Esto es un poco más dificil.
    Imaginemos un usuario que interactua con la calculadora. El usuario ingresa un número,
    luego una operacion, después otro número y despues presiona otra operación (o el igual) que es cuando espera que aparezca el resultado.
    Si hace 12 + 4 sqrt = el resultado que se espera sera 14 y no 4. Las operaciones de 2 operandos deben ser retrasadas hasta la próxima operación o hasta que se presione el igual.

    42. Volvemos a CalculatorBrain.h y agregamos 2 variables de instancias que necesitaremos para las operaciones de 2 operandos: una variable para la operación que esta esperando ser ejecutada hasta que se presione el otro operando y la otra para la siguiente operación.

    @interface CalculatorBrain : NSObject {
    
    double operand;
    
    NSString *waitingOperation;
    
    double waitingOperand;
    }
    - (void)setOperand:(double)aDouble;
    - (double)performOperation:(NSString *)operation;
    
    

    43. Volvemos a CalculatorBrain.m. Esta es una implementación que soporta 2 operandos performOperation:

    - (double)performOperation:(NSString *)operation
    {
        if ([operation isEqual:@"sqrt"])
        {
            operand = sqrt(operand);
        }
        else
       {
            [self performWaitingOperation];
            waitingOperation = operation;
            waitingOperand = operand;
       }
       return operand;
    }
    

    Basicamente si se le pide a CalculatorBrain que realice una operación que no es simple (código invocado por el else) entonces CalculatorBrain llama al método performWaitingOperation (que todavía no hemos escrito) para realizar waitingOperation

    - (double)performOperation:(NSString *)operation
    {
        if ([operation isEqual:@"sqrt"])
        {
            operand = sqrt(operand);
        }
        else if ([@"+/-" isEqual:operation])
        {
            operand = - operand;
        }
        else
        {
      [self performWaitingOperation];
      waitingOperation = operation;
      waitingOperand = operand;
        }
     return operand;
    }
    

    Todavía necesitamos implementar performWaitingOperation.
    Cuando el mensaje es enviado a self significa que el mensaje se envia a si mismo. Otros lenguajes lo llaman this. performWaitingOperation es un método privado por lo tanto no lo pondremos en CalculatorBrain.h si no que ira en CalculatorBrain.m.

    44. Esta es la implementación de performWaitingOperation. Es importante que este código lo pongas en tu archivo CalculatorBrain.m  en alguna parte antes de la implementación de performOperation:.
    Esto es porque performWaitingOperation es un método privado. No se encuentra en la API pública. Debe ser declarado o definido antes de ser usado en un archivo. El mejor lugar es quizás entre la  implementación de  setOperand: y la de performOperation:.

    - (void)performWaitingOperation
    {
        if ([@"+" isEqual:waitingOperation])
        {
    
            operand = waitingOperand + operand;
        }
        else if ([@"*" isEqual:waitingOperation])
        {
    
            operand = waitingOperand * operand;
        }
        else if ([@"-" isEqual:waitingOperation])
        {
    
            operand = waitingOperand - operand;
        }
        else if ([@"/" isEqual:waitingOperation])
       {
    
           if (operand) 
           {
               operand = waitingOperand / operand;
           }
    
       }
    }
    

    Usamos la sentencia if {} else para que waitingOperation pueda utilizarce con cualquier operación despues realizamos la operación usando el operando actual y el que estaba esperando  (waitingOperand).
    Nuestro modelo esta implementado. Lo único que nos falta es hacer el controlador.


    Parte 6: 
    Implementar el controlador

    Lo que nos falta codificar es lo que sucede cuando se presiona un dígito (digitPressed:) o una operación (operationPressed:). Este código ira en nuestro CalculatorViewController. Ya hemos declarado estos métodos en la cabecera archivo (.h) , pero ahora tendremos que hacer la implementación en el archivo .m.


    45. Abrimos CalculatorViewController.m y seleccionamos y borramos todo el código de ayuda (“helpful” code) que se encuentra entre  @implementation y @end.

    46. Ahora volvemos a to CalculatorViewController.h y copiamos las dos declaraciones
    de los métodos en CalculatorViewController.m entre  @implementation y @end. Borramos los punto y coma y lo reemplazamos por  { } (llaves vacías). Debería verse así:


    //CalculatorViewController.m
    //Calculator
    //Copyright Stanford CS193p. All rights reserved.
    
    #import "CalculatorViewController.h"
    @implementation CalculatorViewController
    - (IBAction)digitPressed:(UIButton *)sender
    {
    }
    - (IBAction)operationPressed:(UIButton *)sender
    {
    }
    @end
    
    


    Veamos ahora un truco de debugging. Hay dos técnicas principales  de debuging, una es utilizar el debugger  que viene con el programa y la otra es usar printf, Objective-C provee la funcción NSLog() para esto. Vamos a utilizar NSLog() en  operationPressed: y después vamos a ejecutar nuestra calculadora y ver en la consola el resultado.


    El primer argumento es un NSString ( no una constante  char *, por eso no olvidar @), y el resto de los argumentos son los valores para cualquier campo % en el primer argumento. Un nuevo tipo del campo % ha sido agregado, %@, que significa que el argumento correspondiente es un objeto.

    47. Veamos este ejemplo con el método operationPressed:

    - (IBAction)operationPressed:(UIButton *)sender
    {
        NSLog(@"The answer to %@, the universe and everything is %d.", @"life", 42);
    }
    


    Si hacemos click en un botón que realiza una operación nos aparecerá “The answer
    to life, the universe and everything is 42.” ¿pero donde lo vemos?

    48. Luego vamos al menú Run en Xcode y elegimos Console. Nos aparecerá una ventana. Ahí será donde veremos la salida. También se puede hacer click en Build and Run (o Build and Debug)  en esa ventana para ejecutar el programa desde ahí. Hacemos click en una operación y deberíamos ver algo así:




    49. Reemplacemos la implementación de NSLog(). Notar que el argumento para operationPressed: es el botón que nos esta enviando el mensaje. Le preguntaremos a quien nos envia el nombre del botón (titleLabel, los objetos UIButton usan objetos UILabel ) ,luego preguntamos el UILabel retornado para saber el texto.  El resultado sera un NSString  con un  + ó * ó / ó - ó = ó sqrt.

    - (IBAction)operationPressed:(UIButton *)sender
    {
        NSString *operation = [[sender titleLabel] text];
    }
    
    




    50. Lo que necesitamos ahora es setear la variable Brain, para eso vamos a crear un método que cree y que retorne nuestra variable. Vamos a ponerlo justo antes de  @implementation.


    - (CalculatorBrain *)brain
    {
        if (!brain) brain = [[CalculatorBrain alloc] init];
      return brain;
    }
    


    Basicamente queremos crear una variable brain, por eso hacemos la creación de la misma si esta no existe. Creamos la variable brain y la inicializamos.

    51. Ahora que tenemos en el método CalculatorViewController.m que retorna a CalculatorBrain (nuestro Modelo)  vamos a usarlo.

    - (IBAction)operationPressed:(UIButton *)sender
    {
        NSString *operation = [[sender titleLabel] text];
        double result = [[self brain] performOperation:operation];
    }
    
    



    52. Tenemos el resultado de nuestra operación, solo necesitamos mostrarla en el display, para esto enviamos el mensaje setText:  a nuestro display outlet (recuerden que esta ligado al UILabel en nuestra Vista View). El argumento que vamos a pasar es un NSString creado utilizando stringWithFormat:. Es como printf() o NSLog() pero para objetos NSString. Notar que estamos enviando un mensaje directamente a una clasee NSString  (ni es una instancia de la clase sino la clase en si misma). Así es como creamos los objetos.

    - (IBAction)operationPressed:(UIButton *)sender
    {
        NSString *operation = [[sender titleLabel] text];
        double result = [[self brain] performOperation:operation];
    }
    




    53. Volvemos a CalculatorViewController.h y agregamos la variable de instancia userIsInTheMiddleOfTypingANumber. Este tipo de dato es BOOL y es una versión del tipo de dato booleano en Objective-C’s . Puede tomar dos valores, YES or NO.


    @interface CalculatorViewController : UIViewController {
    
        IBOutlet UILabel *display;
        CalculatorBrain *brain;
        BOOL userIsInTheMiddleOfTypingANumber;
    }
    
    

    54. Ahora volvamos a  CalculatorViewController.m y agregamos código a operationPressed: que lo que va a hacer es chequear si estamos tipeando un número y si es así actualizará el operando de CalculatorBrain para que sea el que ingreso el usuario (luego no sucedera más esto de estar en el medio del tipeo de un número).

    - (IBAction)operationPressed:(UIButton *)sender
    {
    
        if (userIsInTheMiddleOfTypingANumber) {
    
            [[self brain] setOperand:[[display text] doubleValue]];
    
            userIsInTheMiddleOfTypingANumber = NO;
    
        }
    
        NSString *operation = [[sender titleLabel] text];
    
        double result = [[self brain] performOperation:operation];
    
        [display setText:[NSString stringWithFormat:@"%g", result]];
    }
    
    

    Pero cuando se setea userIsInTheMiddleOfTypingANumber ? Bueno, se setea cuando el usuario empieza a ingresar dígitos. De todas maneras necesitamos implementar DigitPressed.
    Pensemos en la lógica de este método. Hay dos situaciones diferentes cuando hacemos click sobre un dígito. El usuario puede estar ingresando un dígito, en este caso agregamos el dígito a lo que ya venia digitando o no y en este caso es cuando queremos mostrar en el display ese digito y hacer notar que estamos ingresando un número.


    55. Agreguemos nuestra primera linea de código para digitPressed:. Nos va a retornar el dígito que fue presionado desde el titleLabel del UIButton que envio digitPressed:mensaje (el que envio).

    - (IBAction)digitPressed:(UIButton *)sender
    {
        NSString *digit = [[sender titleLabel] text];
    }
    
    

    56. Ahora que tenemos el dígito, lo agregamos a lo que ha sido tipeado (usando otro método NSString llamado stringByAppendingString:) o lo seteamos para que sea el nuevo número que estamos tipeando y hacer notar que comenzamos a tipear.

    - (IBAction)digitPressed:(UIButton *)sender
    {
    
        NSString *digit = [[sender titleLabel] text];
    
        if (userIsInTheMiddleOfTypingANumber)
        {
            [display setText:[[display text] stringByAppendingString:digit]];
        }
        else
        {
            [display setText:digit];
            userIsInTheMiddleOfTypingANumber = YES;
        }
    }
    
    

    Quizas se pregunten si  userIsInTheMiddleOfTypingANumber comienza con un NO.
    Sí, lo hace porque los objetos que heredan de NSObject  obtienen todas las instancias seteadas a cero. El cero para un valor del tipo BOOL es igual a NO. Hay que tener cuidado si el mensaje retorna un C struct (en este caso el resultado es indefinido).
    Eso es todo, ahora deberíamos ejecutar nuestra aplicación y ver si no tenemos ningún error de sintaxis.


    miércoles, 26 de enero de 2011

    Parte 1 - MVC para comenzar a programar Cocoa/Objective-C

    MVC - Modelo Vista Controlador

    La idea con el patrón MVC es dividir la aplicación en estas tres capas.





    La capa de Modelo: en el modelo debemos definir de que se trata la aplicación y no como se muestra la aplicación. Si tomamos como ejemplo un juego de naves espaciales, el modelo se refiere a que armas hay, que daño hacen esas armas o en que naves están esas armas.





    La capa controlador: Se encarga de como el modelo es presentado al usuario. Es decir que para un iphone el controlador sera diferente que para un ipad porque cada una de las pantallas es diferente.





    La capa vista: es quien se encarga de servir al controlador. Es lo que utiliza el controlador para hacer su tarea. Es responsable de como se muestra la información en la pantalla.

    ¿Puede la vista enviar mensajes al controlador? no exactamente. Los objetos de la vista son genéricos como botones o labels y no queremos que estos importen el .h de nuestro controlador, para esto existen tres mecanismos que hacen posible esta comunicación:

    1. Target Action: el controlador maneja un target y una acción en la vista, cuando por ejemplo se toca el botón se manda la acción al target.
    2. Delegación: a veces la vista necesita sincronizarse con el controlador o saber que se supone que debería hacer en un caso determinado para esto hay instancias en la vista llamadas delegates que preguntan al controlador que deberían realizar porque necesitan más información para realizar la acción.
    3. Data Source: protocolo que permite que la vista disponga de los datos.

    La vista no es dueña de los datos que muestra, por eso, si necesita de ellos debe obtenerlos a través del controlador. La función de los controladores es interpretar la información que viene del modelo para poder pasársela a la vista.
    El controlador siempre puede comunicarse directamente con el modelo y con la vista, pero la vista con el modelo no pueden hacerlo directamente.

    Pdf en ingles: Lecture 1