icono_twiter icono LinkedIn icono Facebook Icono Xing
Roberto Canales Mora

Creador y propietario de AdictosAlTrabajo.com, Director General de Autentia S.L., Ingeniero Técnico de Telecomunicaciones y Executive MBA por el Instituto de Empresa 2007.
Twitter:

Autor de los Libros: Planifica tu éxito: de aprendiz a empresario y Informática profesional, las reglas no escritas para triunfar en la empresa

Puedes consultar mi CV y alguna de mis primeras aplicaciones (de los 90) aquí

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2010-02-16

Tutorial visitado 11.145 veces Descargar en PDF
Aprendiendo Objetive-C desarrollando para nuestro Iphone 3Gs.

Puedes descargar el código fuente aquí

Aprendiendo Objetive-C desarrollando para nuestro Iphone 3Gs

Antecedentes

Julián, mi proveedor de mamparas y muebles de oficina ( http://www.provimobelmamparas.com ) me dijo hace meses que el iphone era el mejor teléfono que había tenido. Al principio no me parecía la mejor opción por el tamaño y fundamentalmente por no tener GPS. Yo era más bien de htc, y he tenido casi toda la gama. Al surgir el modelo 3Gs me he animado a coger uno y … es el mejor móvil que he tenido nunca. De hecho, otra vez me doy cuenta de que no tenía razón y de haberlo adquirido antes (incluso el modelo anterior) seguro que me hubiera interesado en su programación hace tiempo.

Lo bueno de no ser el primero es que ya hay multitud de ejemplos y libros sobre el tema por lo que "no pagas tanto las novatadas". Además, desde que algo surge hasta que las empresas en España lo demanden creedme que pasan muchos meses.

He visto que algunos miembros de Autentia tienen también el htc con Android con unas sensaciones igual de buenas y … parece que hay una feroz competencia que dará mucho juego. Android tiene como ventaja de partida para nosotros los Javeros, que se programa en Java pero corremos también el peligro de entrar en el anti-patrón golden hammer (para un martillo de oro todos son clavos): No estaría bien elegir un dispositivo solamente porque usa el lenguaje que conocemos…

De momento me ha gustado la vistosidad de Iphone y como el lenguaje y entorno me es completamente nuevo estoy bastante picadillo porque veo decenas de posibles combinaciones con las aplicaciones empresariales que habitualmente nos piden. Aunque trabajemos habitualmente con JSF, Spring y cosas similares: interfaces ricos basados en Iphone o android y tirando de servicios Web y de nuestros componentes SOA, no parece descabellado. Adicionalmente para fortalecer el interés en aprender estas cosas, creo que el IPad (sobre todo una segunda generación futura que me arriesgaría a apostar sale a los pocos meses del primero) nos abrirán un mundo de posibilidades cambiando la percepción del interfaz de usuario… el tiempo lo dirá.

Aunque hay centenares de documentos cuanto te registras en la Web de Mac, empezar me ha requerido leerme un montón de cosas e incluso buscar por internet hasta cuadrar un poco los conceptos. En este tutorial pretendo presentar un poquito el lenguaje, un planteamiento básico de aplicación y las herramientas más comunes a la hora de desarrollar. Siendo egoísta, este tutorial me valdrá a mí para copiar y pegar en otros ejemplos porque al principio la notación se hace un poco extraña por el vicio de Java. Esto es como sacarte el carnet de conducir cuando has llevado desde los 15 años coches por el campo … tienes muchos vicios.

Por cierto, que no se os olvide visitar el tutorial anterior que tengo sobre esto. Seguro que os quedarán las cosas más claras. http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=scrumiphone

Ejemplo a realizar

En mis cursos de UML y orientación a objetos, pongo siempre un ejemplo de lo simple que puede plantearse un sistema para pintar si tenemos claros los conceptos de polimorfismo.

El sistema consistirá en:
  • Una clase base que represente un objeto gráfico y defina los atributos comunes y los métodos a redefinir. Será CObjetoGrafic
  • Una clase derivada por cada objeto gráfico a pintar: Básicamente como un patrón estrategia. Serán CRectangulo y CElipse.
  • Un vista que controle los eventos del dedo (o ratón en el simulador) que diga donde pintar.
  • Unos botones que nos ayuden a definir si pintamos una elipse o un rectángulo.
  • Un controlador que reciba los eventos de los botones y establezca el tipo de elemento a pintar.
En principio parece muy fácil pero creedme que me ha llevado unas cuantas horas llegar al código adecuado. El mejor recurso ha sido mirar en los ejemplos del propio Iphone y sacar las referencias a la documentación.

Entorno


MacBook pro 13 pulgadas con pantalla auxiliar (es fundamental para trabajar cómodo).


Developer Information:
Version: 3.2 (10M2003)
Location: /Developer
Applications:
        Xcode: 3.2.1 (1613)
Interface Builder: 3.2.1 (740)
Instruments: 2.0.1 (1096)
Dashcode: 3.0 (328)
SDKs:
Mac OS X:
           10.5:(9J61)
           10.6:(10M2003)
iphone OS:
           2.2.1: (5H11)
           3.0:(7A341)
           3.1:(7C144)
           3.1.2:(7D11)
iphone Simulator:
           3.0:(7A341)
           3.1:(7C144)
           3.1.2:(7D11)

Creación del esqueleto del proyecto con el wizard de xcode

Creamos el proyecto basado en una vista y lo llamamos PintadorIphone

Examinamos el proyecto base

Vamos a insertar los iconos de la aplicación y el de por defecto.

Pintando el icono con Icon Composer.


Vamos a revisar las herramientas que vienen con el Kit de desarrollo para el Iphone y encontramos ésta: Icon Composer.

Copiamos un área de pantalla (una captura del simulador del Iphone con el programa terminado)

Y previsualizamos a ver cómo queda

Guardamos en el raíz de nuestro proyecto el icono. Le podemos dar a convertir a ICO

Vemos que baja un poquito el tamaño

Pero el Iphone necesita que el fichero tenga extensión png (lo he probado en .ico no funciona). El .ico lo abrimos con vista previa de Mac

Lo guardamos como png y ya está la conversión hecha.
También lo guardamos como Default.png para que nos valga de pantalla flash (aunque podría ir aquí publicidad o algo más vistoso)

No se nos debe olvidar ir a la carpeta de recursos y añadir los ficheros existentes

Ya tenemos el icono. Arrancamos el simulador del Iphone para comprobarlo

Añadiendo clase de vista

Nosotros vamos a hacer un programa que pinte atendiendo a los toques de la pantalla táctil de nuestro Iphone o simulando con el ratón en el emulador.
Al crear el proyecto desde el asistente, se crea un fichero que contiene nuestra vista. Ahora bien, como queremos redefinirla, necesitamos el código fuente de la clase derivada de UIView para, a través de polimorfismo de nuevo, redefinir los métodos deseados.

Nos vamos a xcode y en el menú file creamos un nuevo fichero (New Empty File)

El el combo desplegable elegimos la clase base UIView

Y le damos el nombre CAreaPintadoView. Es bueno ser coherente con la notación. De hecho muchas cosas en Objetive-C se basan en respetar convenciones en la nomenclatura.

Vamos a repetir el proceso para crear las clase: CObjetoGrafico, CRectangulo y CElipse

Vemos un ejemplo para ver que ahora derivan de NSObject, sobre todo nos importa CObjetoGrafico porque las demás las vamos a cambiar a mano para que dependan de ella.

También vamos a crear un prototipo simplemente por practicar. Es como un interfaz en Java. Sólo nos interesa el .h pero nos crea los dos ficheros. Por convención (mía) le hago que empiece por I mayúscula.

El punto m nos lo cargamos ya que no tiene sentido para nuestro protocolo.

En la siguiente pantalla podemos elegir borrar solo la referencia o mandar el fichero en sí a la papelera… como más os guste aunque yo prefiero borrarlo.

Establecer la clase manejadora de la vista

Ahora nos vamos al interfaz gráfico pinchando en cualquier fichero xib (mejor el controlador). Veremos que la vista (View a la izquierda) es de tipo UIView. Lo cambiamos a CAreaPintadoView.

Ahora tenemos que buscar un buen punto para hacer las inicializaciones de nuestras variables.
Redefinimos el método initWithCoder que es invocado al crear las vista. Es un buen punto para coger otros recursos que podamos tener almacenados dentro del fichero nib.

//
// CAreaPintadoView.m
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright 2010 Autentia. All rights reserved.
//

#import "CAreaPintadoView.h"
@implementation CAreaPintadoView

// Metodo invocado cuando se carga desde un nib -initWithCoder:
- (id)initWithCoder:(NSCoder*)coder {
      [super initWithCoder:coder]; // no olvidar invocar al padre para que se pinte el nib
      
      NSLog(@"Cargamos desde nib, buen momento para inicializar cosas");
      
      return self;
}

Manejarnos por la documentación y pdfs recomendados

Es vital saber saltar rápidamente a la documentación. Elegimos una palabra y pulsamos el botón derecho

Al principio la documentación puede parecer confusa … pero cuando te acostumbras a ella se maneja muy bien.

Yo pulso el botón de pdf a la derecha y me bajo toda la documentación en un solo documento pdf para leer en mi Kindle Dx.
Ésta es una colección de los pdfs que os recomiendo que encontréis.

Como véis, no me he aburrido pero todavía me queda una segunda y tercera lectura de cada uno de ellos.
Como se suele decir, para estar bella hay que sufrir… pues para saber, hay que estudiar.

Construir y ver lo que pasa en la consola.

El método NSLog vuelca en la consola mensajes que nos puede permitir ver de un modo cómodo qué pasa.

Además nos permite arrancar desde aquí la construcción y depuración

Si arrancáis el programa y no sale nada en los lo de la consola de xcode ¿qué puede ser?
Si estáis acostumbrados a C/C++ os vendrá a la idea de un modo inmediato el problema… problemas de linkado (perdonad el palabro).
En Bulid pulsamos Clean All Targets

Borramos todo

Volvemos a ejecutar y ya nos aparecen los comentarios. No se había enterado el builder de la asociación de una nueva vista (o eso parece).

Ahora vamos a revisar los resultados de la construcción. En el menú Build pulsamos Build Results

Vemos que de momento no tenemos problemas pero deberíamos en el futuro vigilar que tampoco tenemos Warnings.

Creando el comportamiento polimórfico

Queremos que todas las clases que pinten tengan la función pintate y que reciban el contexto de dibujo. Creamos un protocolo a tal fin llamado IPintable

// IPintable.h
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright 2010 Autentia. All rights reserved.
//

#import < Foundation/Foundation.h>

@protocol IPintable // es el equivalente a un interfaz en java

@required // declaramos el método como requerido     
-(void) pintate:(CGContextRef *) contexto;

@end

 

Ahora vamos a crear la clase CObjetoGrafico que implementa pintable y que tiene las variables x,y,ancho y alto. También construimos un inicializador que por defecto empieza por init y que retorna self.
También proporcionamos un método auxiliar de traza para ver el estado de las variables sin recurrir al depurador.

Vemos el fuente.

#import < Foundation/Foundation.h>
#import "IPintable.h"
@interface CObjetoGrafico : NSObject < IPintable> { // No se puede declarar una clase abstracta en Objetive-C
      @protected // atributos protegidos porque queremos usarlos en clases derivadas polimorficas
      NSInteger x; // punto x inicial donde pintar la figura
      NSInteger y; // punto y inicial donde pintar la figura
      NSInteger ancho; // ancho de la figura
      NSInteger alto; // alto de la figura
}

// ojo que las propiedades no assign hay que liberarlas en dealloc
@property NSInteger x;
@property NSInteger y;
@property NSInteger ancho;
@property NSInteger alto;

// creamos el inicializador con los nombres de los atributos
-(id) initConValores:(NSInteger) px y:(NSInteger)py ancho:(NSInteger)pancho alto:(NSInteger)palto;

-(void) traza; // metodo para volcar en la consola el contenido de las variables

@end

// Como repaso, si queremos utilizar métodos particulares en clases hijas, recondar:
// isMemberOfClass verifica si es de una clase concreta
// isKindOfClass verifica si es de una derivada

 

Vemos ahora la implementación en el fichero .m

De momento todo sencillito

//
// CObjetoGrafico.m
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright 2010 Autentia. All rights reserved.
//

#import "CObjetoGrafico.h"
@implementation CObjetoGrafico
@synthesize x; // getters y setters automaticos
@synthesize y; // getters y setters automaticos
@synthesize ancho; // getters y setters automaticos
@synthesize alto; // getters y setters automaticos

// inicializamos la clase base
-(id) initConValores:(NSInteger) px y:(NSInteger)py ancho:(NSInteger)pancho alto:(NSInteger)palto
{
      self = [super init]; // leer convenciones
      self.x = px;
      self.y = py;
      self.ancho = pancho;
      self.alto = palto;
      return self; // simpre retornar self
}


-(void) traza // mostramos el contenido
{
      NSLog(@"valor X: %d",x);
      NSLog(@"valor Y: %d",y);
      NSLog(@"valor Ancho: %d",ancho);
      NSLog(@"valor Alto: %d",alto);
      NSLog(@"--------------");
}


// método base que pinta un rectangulo por defecto
-(void) pintate:(CGContextRef *) contexto
{
}
@end


La clase CRectangulo hacemos que herede de CObjetoGrafico y hacemos lo mismo con CElipse.

Ver la relación de clases como modelo UML

Si pinchamos en la raíz del proyecto y damos a Design > Class Model > Quick Model

Podremos ver las relaciones de asociación, herencia, implementación que se van creando. Podemos hacerlo eligiendo otra clase cualquiera.

Creando botones en la vista y la acción ejecutora para cambiar el elemento a pintar.

Si volvemos al builder, arrastamos una barra de navegación y dos botones. No es que sea tal vez el control más adecuado pero queremos hacerlo muy simple.
Ponemos en los botones los títulos Elipse y Rect (ignorar que pone rectángulo o si cambiáis el título que sepáis que tiene impacto el el código posterior).

Si os fijáis a la derecha en Library, hemos elegido la clase PintadoriphoneViewController y hemos creado la acción botonPulsado que retorna un UIBarButtonItem (por defecto es un id).

Ahora deberíamos pinchar la rueda con engranajes de abajo y guardar los cambios en el controlador … pero como no me fío, lo vamos a hacer a mano (si queréis podéis ver el merge.. como en el tutorial anterior describía http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=scrumiphone)

Hay que cambiar el .h para registrar la acción como método de tipo IBAction

//
// PintadoriphoneViewController.h
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright Autentia 2010. All rights reserved.
//

#import < UIKit/UIKit.h>

@interface PintadoriphoneViewController : UIViewController {
}

// método común a pulsar cualquiera de los botones
-(IBAction)botonPulsado:(UIBarButtonItem *)sender;

@end


Y también el .m

Donde vamos a pasar a la vista el tipo de elemento a pintar según se pulse el botón. Utilizaremos su propiedad pública "tipo".Usaremos una única función por lo que en base al título del botón elegimos qué pintar.

Esto es un poco chapuzas porque hay más modos de hacerlo, como usar otras propiedades como el tag … pero así veis cómo se comparan cadenas.


//
// PintadoriphoneViewController.m
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright Autentia 2010. All rights reserved.
//

#import "PintadoriphoneViewController.h"

@implementation PintadoriphoneViewController

// al pulsar los botones modificamos los atributos de la vista
- (IBAction)botonPulsado:(UIBarButtonItem *)sender {
// Asociamos la vista a nuestra vista (un casting explicito no vendría mal comprobando el tipo)
      CAreaPintadoView* vista = [self view];
      // interesante ver como se comparan dos cadenas ... muy al estilo de Java
      if([[sender title] isEqualToString:@"Rect"] == TRUE)
      {
            NSLog(@"Pues es un rec");
            vista.tipo = 0;
      }
      else if([sender.title isEqualToString:@"Elipse"] == TRUE)
      {
            vista.tipo = 1;
            NSLog(@"Pues es una elipse");
      }
}

Yo ahora cerraría el interfaz builder y lo volvería a abrir para que coja la acción.
Que no se os olvide que hay que asociar ahora los botones a la acción.

Con control pulsado o con el botón derecho elegimos el ratón y lo arrastramos a File´s Owner que nos mostrará las acciones disponibles.
Repetimos el proceso para los dos botones.

Incorporar el comportamiento de pintado

Ahora en la vista vamos a apoyarnos en un array de tipo NSMutableArray que nos permite añadir objetos dinámicamente sin clave.
Cuando el usuario pulse la pantalla nos quedaremos con la primera coordenada y la guardaremos en ítem e ítem.
Al dejar de tocar la pantalla cogeremos las coordenadas y restando a las anteriores calcularemos en ancho y alto.


// CAreaPintadoView.h
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright 2010 Autentia. All rights reserved.
//

#import < UIKit/UIKit.h>
// Clase base que asociamos al nib como vista

@interface CAreaPintadoView : UIView {
@private
      NSMutableArray* arrayObjetos; // array de objetos a pintar
      NSInteger xtem; // variables auxiliares para boton pulsado
      NSInteger ytem;
      NSInteger anchotem; // variables auxiliares para boton soltado
      NSInteger altotem;
@public
      NSInteger tipo; // tipo
}

@property NSInteger tipo;
@end

Probamos cómo lo llevamos hasta ahora y en la ventana de build verificamos si hay algún error … a mi me falta un .h que añado.

Todo funciona de momento bien … y vemos nuestra pantalla con sus botones.

Aprender a depurar

A estas alturas deberíamos ya saber usar el depurador. Esto sí que es realmente intuitivo y parecido a otros lenguajes.
En el editor de código podemos pinchar a la izquierda (el área gris más gorda) para marcar un punto de interrupción.

En Run usamos el menú Debugger

Os recomiendo que activéis el ver el tipo de objetos (que suele ser fuente de errores)

Y vemos el tipo de cada elemento

Recordad que cuando pasan cosas raras… no es el entorno el que las hace "ERES TÚ".
Para desactivar los puntos de parada o breakpoints en xcode podemos quitarlos arrastrando las flechitas fuera o a través del menú.

Pintando en la pantalla

La clave del código de pintado está en CAreaPintadoView

Al soltar el dedo (bueno esto queda un poco raro dicho) creamos una referencia de tipo objeto gráfico y lo inicializamos en la clase derivada hija.
Luego metemos el objeto en un array que recorreremos cada vez que sea necesario pintar.

Realmente esto no se haría así porque siempre es necesario usar doble-buffers: creas un contexto de tipo imagen que representa la pantalla, pintas en la imagen y luego vuelcas solo la imagen en la pantalla. Así es mucho más eficiente y se crean menos objetos.

 //
// CAreaPintadoView.m
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright 2010 Autentia. All rights reserved.
//
#import "CAreaPintadoView.h"
#import "CoreGraphics/CoreGraphics.h"
#import "CObjetoGrafico.h"
#import "CRectangulo.h"
#import "CElipse.h"

// clase donde imlementamos todo el código particular de pintado
@implementation CAreaPintadoView

@synthesize tipo; // nos ivocarán desde clases externas

// Metodo invocado cuando se carga desde un nib -initWithCoder:
- (id)initWithCoder:(NSCoder*)coder {
      [super initWithCoder:coder]; // no olvidar invocar al padre para que se pinte el nib
      NSLog(@"Cargamos desde nib, buen momento para inicializar cosas");
      arrayObjetos = [[NSMutableArray alloc] init ]; // inicializamos el array
      tipo = 0; // ponemos un tipo 0 por defecto
      return self;
}

- (id)initWithFrame:(CGRect)frame {
      if (self = [super initWithFrame:frame]) {
      // Initialization code
}

NSLog(@"Inicializamos el frame");
      return self;
}

// cojemos la pulsación inicial
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
      NSLog(@"Pulsado");
      CGPoint primerPunto;
      for (UITouch *touch in touches) {
          primerPunto = [touch locationInView:self]; // recuperamos coordenas locales
          break; // ignoramos resto de touches
      }

      xtem = primerPunto.x; // Asociamos las auxiliares
      ytem = primerPunto.y;
}


// de momento no nos interesa el movimiento
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
      // NSLog(@"Movido");
}


// al levantar los dedos
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
      CObjetoGrafico* temporal = nil; // creamos una objeto de la clase base
      CGPoint ultimoPunto; // recuperamos coordenas
      for (UITouch *touch in touches) { // ete bloque es igual que al pulsar pero no refactorizamos aposta
              ultimoPunto = [touch locationInView:self];
              break;
      }


      anchotem = ultimoPunto.x - xtem; // calculamos ancho y alto
      altotem = ultimoPunto.y - ytem;
      if( tipo == 0) // en función del tipo creamos un objeto distinto para usar polimorfismo
      {
            NSLog(@"Creamos rect");
            temporal = [[CRectangulo alloc] initConValores:xtem y:ytem ancho:anchotem alto:altotem];
      }
      else if (tipo == 1)
      {
            NSLog(@"Creamos elipse");
            temporal = [[CElipse alloc] initConValores:xtem y:ytem ancho:anchotem alto:altotem];
      }
      else {
            NSLog(@"Error al elegir el tipo objeto");
            return;
      }
      
      NSLog(@"Soltado");
      
      [arrayObjetos addObject:temporal]; // añadimos elemento al array
      
      // indicamos que hay que refrescar la vista
      [self setNeedsDisplay]; // ojo que no lleva el :YES como aparece en algunos sitios de la doc
}


- (void)drawRect:(CGRect)rect { // código invocado al pintar

          NSLog(@"Pintamos --En el CAreaPintado");
          
          CGContextRef contexto = UIGraphicsGetCurrentContext();
          
          // Pintar los objetos delegando en la función polimorfica
          for ( CObjetoGrafico *elemento in arrayObjetos) { // usamos las enumeraciones rápidas
                [elemento traza]; // mostramos los datos en la consola de depuración
                [elemento pintate:contexto]; // pasamos contexto
          }
}

// como hemos hecho alloc debemos limpiar la memoria. Nunca se invoca dealloc directamente
- (void)dealloc {

[super dealloc];
      NSLog(@"Borramos memoria");
      // no se nos olvide limpiar los objetos del array
      for ( CObjetoGrafico *elemento in arrayObjetos) { // recorremos el array y pintamos
            [elemento release];
      }
      [arrayObjetos release]; // limpiamos el array en si mismo.
}

@end



Ahora añadimos el código de pintado en la clase CObjetoGrafico

Pintamos un rectángulo relleno. Como el comportamiento es polimorfo todo debería funcionar ya … aunque eligiendo elipses o rectángulos pintaría lo mismo.

// método base que pinta un rectangulo por defecto

-(void) pintate:(CGContextRef *) contexto
{
      NSLog(@"Pintamos un rectangulo por defecto");
      CGContextSaveGState(contexto); // guardardamos el contexto
      CGContextSetRGBFillColor(contexto, 255.0, 0.0,0.0,1.0); // ponemos el color rojo por defecto
      CGRect rec = CGRectMake(x, y, ancho, alto); // inicializamos el rectangulo
      CGContextFillRect(contexto,rec); // pintamos el rectangulo
      CGContextRestoreGState(contexto); // recuperamos el contexto
      // para saber si una clase conforma un protocolo conformsToProtocol:@protocol(clase)
}  
   
   
   

Hacer una foto (snapshot) del código actual

Hemos llegado a un punto muy estable de código y sería una pena entrar en una espiral de violencia y perder fuentes. Siempre es conveniente usar un repositorio tipo CVS, subversion u otras opciones de pago.
A falta de uno, podemos hacerlo localmente creando un SnapShot.

Lo hacemos periódicamente y le ponemos un nombre

Podemos ver los cambios de código desde el Snapshot

Y compararlos e incluso recuperar los fuentes

Código en función polimorfa para pintar elipse

Ahora vamos a pintar las elipses


Creamos una función auxiliar
//
// CElipse.h
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright 2010 Autentia. All rights reserved.
//

#import < Foundation/Foundation.h>
#import "CObjetoGrafico.h"

@interface CElipse : CObjetoGrafico { // no necesitamos definir los métodos a redefinir
}


-(CGPathRef)creaCirculo; // método auxiliar de instancia para crear la mascara de un circulo

@end

Realmente simple vamos a usar la misma función para pintar un área rectangular pero la vamos a alterar con patrones de transformación.


// CElipse.m
// Pintadoriphone
//
// Created by rcanales on 13/02/10.
// Copyright 2010 Autentia. All rights reserved.
//

#import "CElipse.h"
#import "CoreGraphics/CoreGraphics.h"

@implementation CElipse
-(void) pintate:(CGContextRef *) contexto
{
      CGContextSaveGState(contexto); // Guardamos los atributos del contexto
      CGRect rec = CGRectMake(x, y, ancho, alto); // creamos un rectangulo
      CGContextSetRGBFillColor(contexto, 0.0, 255.0 , 0.0 , 0.5); // Cambiamos el color del contexto
      // la elipse es semitransparente
      
      NSLog(@"Pintamos un rectangulo por defecto");
      CGContextAddPath(contexto, [self creaCirculo]); // añadimos el modificador de elipse
      CGContextClip(contexto); // definimos el área de pitando.
      // si no restaurammos el contexto no podríamos pintar fuera
      
      CGContextFillRect(contexto,rec); // pintamos un rectangulo con la máscara alterada
      
      CGContextRestoreGState(contexto); // restauramos el estado del contexto de nuestra vista
      
      // para saber si una clase conforma un protocolo conformsToProtocol:@protocol(clase)
}

-(CGPathRef) creaCirculo
{
      CGMutablePathRef circulo = NULL; // recordar incluir los ficheros de cabecera
      CGRect rec = CGRectMake(x, y, ancho, alto);
      
      circulo = CGPathCreateMutable();
      CGPathAddEllipseInRect(circulo, NULL, rec);
      
      return circulo;
}

@end


Y ya tenemos nuestro programa completo con cuadrados y circulitos pintamos un osito...

Indentar el código

Si habéis copiado o pegado código es bueno indentarlo.

Podemos ver cómo se comporta la aplicación si giramos el dispositivo. De momento no hemos hecho nada para que cambie el compotamiento.

Observar comportamiento de la memoria

Por último vamos a ver la herramienta para comprobar lagunas de memoria pero ésto tenemos todavía que tratarlo con cariño.

Se arranca un monitor donde va grabando el uso de la memoria según usamos nuestro programa. Ahora está parado y podemos pasar el botón por los puntos rojos para ver qué pasa.
Parece que el problema no es nuestro.

Me gusta más hacer las pruebas heurísticas, contar objetos y ver si se nos van quedando por medio.
Si os fijáis, a la izquierda, he elegido Allocation Lifespan/ Created & Still Living. Es decir, quiero ver el número de objetos vivos.

Si voy haciendo cosas y se me dispara … malo.

Pulsando elipse nos fijamos en la columna Living ..

Las herramientas de rendimiento son un mundo y podemos incorporar la monitorización de otros comportamientos (pulsando el botón Library arriba a la derecha)

Bueno, yo creo que por hoy ya está bien … seguiremos investigando sobre las tecnologías de desarrollo de nuestro Iphone, Objetive-C y las herramientas asociadas que creedme que son muchas.
Francamente me encanta (no había estado tan picado desde hace tiempo) . Espero poder compartir con vosotros este nuevo hobby que seguro que tiene miles de salidas en desarrollos empresariales.

A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL:

Fecha publicación: 2011-01-02-23:27:49

Autor: Pipo

hola Roberto

Esta muy bueno el tutorial, me gustaria poder revisar el anterior que hiciste pero no aparece el tutorial, ademas seria bueno para aprender el merge que no lo discutes en este tuto

un saludo gracias

Fecha publicación: 2010-02-16-13:33:38

Autor: rcanales

Hombre, todo es relativo. ¿Hay una versión del Developer Studio para Mac o Linux?

De todos modos yo procuro mantenerme neutral. Es el cliente el que elige y yo quiero tener los conocimientos y herramientas para dar servicio (dentro de nuestros gustos). De todos modos mira la ventaja competitiva... todo el mundo tiene un PC... poca gente en España tiene un Mac. Si aprendes a programar un MAC, la competencia a priori parece menor (y más si hay que usar Objetive-C y no Java)

También decirte que estamos en paralelo con Android ... así podemos comparar.

Fecha publicación: 2010-02-16-13:02:24

Autor: joxeka

Hola Roberto,

esta muy bien el desarrollo para Iphone/IPod, pero me parece algo intolerable que para poder desarrollar para este dispositivo, las mejores herramientas sólo estén disponibles para Mac, y no para PC. Yo en mi caso, me voy a decantar por Android, porque aunque esté mas verde, no necesito gastarme un pastizal para desarrollar en el.

Un saludo