You are on page 1of 21

Tutorial Objective C. Primeros pasos en el desarrollo de aplicaciones para iPhone.

Programar en iOS implica utilizar OSX, el sistema operativo de Apple. Hay dos caminos que nos permiten hacer esto: utilizar un equipo con OSX instalado (recomendable; que la mquina sea un mac es la ruta ms sencilla, aunque es posible instalar OSX en otros ordenadores), o utilizar una mquina virtual. El principal problema con la mquina virtual es que en general, el rendimiento de la mquina emulada va a ser ms pobre. Cualquiera que sea la opcin a elegir, el objetivo es tener OSX instalado y funcionando correctamente. Apple proporciona su propio entorno de desarrollo, Xcode, de forma gratuita a travs de iTunes Store. El paso siguiente es crearse una cuenta de iTunes para poder descargarse el IDE Xcode.

Aqu termina la lista de software necesario para poder programar en iOS, todas las herramientas necesarias las proporciona Xcode.Pasemos a los requisitos a nivel de programacin. iOS admite tres lenguajes de programacin: C, C++ y Objective-C.

Sin entrar en detalles, Objective-C es en esencia C, pero con la capacidad de programacin orientada a objetos similar a SmallTalk. Para crear aplicaciones de iOS, Apple proporciona el API (Application Programming Interface) de Cocoa Touch,basado en el API de Cocoa que se utiliza en OSX; se trata de un conjunto de objetos/funciones que proporcionan una capa de abstraccin: esto permite manejar en cdigo objetos de alto nivel que referencian, por ejemplo, partes del hardware del dispositivo que se vaya a usar, o bien elementos de la interfaz como pueden ser botones u otros controles. Utilizar Cocoa Touch implica utilizar Objective-C, lo que quiere decir que es necesario saber la sintaxis de ste y cmo funciona el envo de mensajes entre objetos. Todas las variables de objetos en Objective-C son punteros. Haciendo una analoga entre C++ y Objective-C, estos ltimos tambin tienen un constructor. Para empezar a utilizar un objeto, puesto que lo que se va a manejar son punteros, lo primero es reservar la memoria (alloc), y despus llamar al constructor (init). Todo esto lo veremos en detalle ms adelante. De momento, olvidmonos de iOS y centrmonos en Objective C.

Introduccin a Objective C
Como es costumbre en tutoriales, la mejor forma de empezar es haciendo un sencillo programa Hola Mundo!. De momento nos centraremos en las principales diferencias entre C/C++ y Objective C, por lo que este primer programa ser en modo consola. < Como crear un programa para consola en XCode, aadir imgenes si hace falta> Programa en C: #include <stdio.h> int main(int argumentCount, const char* arguments[]) { printf(Hola mundo!\n); return 0; }

Programa en Objective-C: #import <stdio.h> int main(int argumentCount, const char* arguments[]) { printf(Hola mundo!\n); return 0; } Existen dos diferencias entre el programa versin C y el de Objective-C: la primera es que en vez de usar #include, usaremos #import para referenciar otras libreras. La otra diferencia es que la extensin de archivos no es .c o .cpp, sino .m. Los archivos de cabecera siguen siendo .h.

Clases en Objective-C
Veamos cmo crear una clase de objeto sencillo en Objective-C. La clase ser de tipo MiObjeto, derivado de la clase fundamental NSObject (NeXTStep Object), que es, digamos, el equivalente a Object en Java del cual se derivan todos los objetos. Puesto que va ser una clase derivada, heredar varios mtodos (funciones) y atributos (variables) propias del objeto NSObject. La descripcin del objeto NSObject se encuentra aqu.

Declaracin de la clase MiObjeto en Objective-C, archivo MiObjeto.h: #import <Foundation/NSObject.h> @interface MiObjeto : NSObject { // Atributo de tipo entero int numeroEntero;

// Atributo de tipo float float numeroFraccionario; } // Mtodo para asignar un valor al atributo numeroEntero -(void) setNumeroEntero: (int) numero; // Mtodo para asignar un valor al atributo numeroFraccionario -(void) setNumeroFraccionario: (float) numero; // Mtodo para mostrar en pantalla el valor de numeroEntero -(void) printNumeroEntero; // Mtodo para mostrar en pantalla el valor de numeroFraccionario -(void) printNumeroFraccionario; // Mtodo que devuelve el valor del atributo numeroEntero -(int) getNumeroEntero; // Mtodo que devuelve el valor del atributo numeroFraccionario -(float) getNumeroFraccionario; @end Como vemos, la definicin del objeto se encuentra entre los delimitadores @interface y @end. La herencia del objeto se describe a continuacin del delimitador @interface: @interface <NombreDeLaClaseDelObjeto> : <NombreDeLaSuperClase> @interface MiObjecto : NSObject La traduccin es la clase MiObjeto es derivada de la clase NSObject Los atributos de la instancia (las variables propias de la clase) se definen dentro de los corchetes: @interface MiObjeto : NSObject { /* Aqu, entre llaves, se definen las variables */ } Si no se especifica el tipo de acceso a las variables, por defecto son protected. Los mtodos/funciones se definen a continuacin de las variables, fuera de los corchetes, pero antes de llegar a@end. El formato es: (tipoDevuelto) nombreDelMtodo: (tipoDeDatoDeEntrada) nombreDelDatoDeEntrada;

-(void) setNumeroEntero: (int) numero; La traduccin es que la funcin setNumeroEntero recibe un dato de tipo int llamado numero, y no devuelve nada. -(int) getNumeroEntero; La traduccin es que la funcin getNumeroEntero no recibe ningn dato, y devuelve un dato de tipo int. El guin (-) que precede la declaracin del mtodo indica que el scope de la funcin es a nivel de instancia. Mtodos que empiezan por - pueden operar con variables propias de cada instancia del objeto. Mtodos que empiezan por + operan a nivel de la clase; digamos que es el equivalente a un mtodo static de un objeto en C++ y en Java. Veamos ahora cmo implementar los mtodos declarados, archivo MiObjeto.m: #import MiObjeto.h #import <stdio.h> @implementation MiObjeto -(void) setNumeroEntero: (int) numero {

// Asignamos a nuestra variable numeroEntero el valor de numero numeroEntero = numero; } -(void) setNumeroFraccionario: (float) numero { //Asignamos a nuestra variable numeroFraccionario el valor de numero numeroFraccionario = numero; } -(void) printNumeroEntero { // Mostramos por pantalla el valor de numeroEntero printf(Numero entero: %d, numeroEntero); } -(void) printNumeroFraccionario {

// Mostramos por pantalla el valor de numeroFraccionario printf(Numero fraccionario: %d, numeroFraccionario); } -(int) getNumeroEntero { return numeroEntero; } -(float) getNumeroFraccionario { return numeroFraccionario; } @end La implementacin de los mtodos declarados en MiObjeto.h se encuentra entre los delimitadores@implementation y @end. La nica diferencia entre la declaracin y la implementacin es que esta ltima contiene la funcin entre llaves, de forma anloga a cmo se realiza en C: -(void) setNumeroEntero: (int) numero { // Lo que tiene que hacer la funcin va aqui } Finalmente, veamos cmo crear nuestro objeto y realizar algunas llamadas a distintos mtodos. El punto de entrada del programa es, al igual que en C, la funcin main(). En Objective C se utilizan punteros a objetos, lo que quiere decir que hay que crear un puntero y reservar memoria para l. Archivo main.m: #import MiObjeto.h int main (int numeroDeArgumentos, const char* argumentos) { // Creamos un puntero a un objeto MiObjeto. Para dar nfasis a que se trata de un puntero, lo inicializamos a nil, que es equivalente a NULL. int otroNumeroEntero = 20; float otroNumeroFraccionario = 3.14; MiObjeto* objeto = nil; // Reservamos memoria para el objeto objeto = [[MiObjeto alloc] init];

// Asignamos un valor al nmero entero del objeto [objeto setNumeroEntero: 10]; // Asignamos un valor al nmero fraccionario del objeto [objeto setNumeroFraccionario: 2.71]; // Mostramos el valor del numero entero que hemos asignado al objeto [objeto printNumeroEntero]; // Mostramos el valor del numero fraccionario [objeto printNumeroFraccionario]; // Asignamos otro valor al numero entero [objeto setNumeroEntero: otroNumeroEntero]; // Asignamos otro valor al numero fraccionario [objeto setNumeroFraccionario otroNumeroFraccionario]; // Mostramos el valor del nuevo numero entero que hemos asignado [objeto printNumeroEntero]; // Mostramos el valor del nuevo numero fraccionario [objeto printNumeroFraccionario]; // Liberamos la memoria reservada para el objeto [objeto release]; return 0; } Como podemos ver, importamos la clase MiObjeto, de forma anloga a como se hara en C/C++. Este es nuestro primer contacto con los corchetes en Objective-C. Los corchetes no son ms que parntesis en realidad, y sirven adems para indicar que se va a acceder a mtodos de Objective C. Veamos qu estamos haciendo al reservar memoria: objeto = [ [MiObjeto alloc] init];

Lo primero que est haciendo esta lnea es [MiObjeto alloc], que va a devolver una direccin de memoria donde se almacenar nuestro objeto (recordemos que objeto es un PUNTERO), y a continuacin, [objeto init], que es la llamada al constructor de la clase. Puesto que nuestro objeto hereda de NSObject, no es necesario declarar el constructor;es decir, no es necesario declarar el mtodo init. Si quisiramos que el objeto hiciera algo distinto en el constructor, o si quisiramos varios constructores, entonces s habra que declararlos.Eso lo veremos ms adelante. Para llamar a un mtodo del objeto, se hace de la forma: [ variableTipoPunteroObjeto nombreDelMetodo: argumentosDelMetodo]; [objeto setNumeroEntero: 10]; En C++ el equivalente sera: objeto->setNumeroEntero(10); En Java el equivalente sera: objeto.setNumeroEntero(10); [objeto printNumeroEntero]; En C++ el equivalente sera: objeto->printNumeroEntero(); En Java el equivalente sera: objeto.printNumeroEntero();

Si quisiramos asignar el numero entero y el fraccionario directamente, tendramos que declarar el mtodo en MiObjeto.h y en MiObjeto.m de esta forma: // En MiObjeto.h -(void) setNumeroEntero: (int) entero yNumeroFraccionario: (float) fraccion;

// En MiObjeto.m -(void) setNumeroEntero: (int) entero yNumeroFraccionario: (float) fraccion { numeroEntero = entero; numeroFraccionario = fraccion; } Para hacer uso del mtodo, lo haramos as: [objeto setNumeroEntero:10 yNumeroFraccionario: 3.14]; En C++, el equivalente sera, suponiendo que existe un mtodo setNumeros que recibe un numero entero y un nmero fraccionario, setNumeros(int ,float): objeto->setNumeros(10, 3.14);

Constructores en Objective-C
Como hemos mencionado antes, MiObjeto hereda el constructor init de NSObject. Supongamos que queremos que al crear un objeto se asignen unos valores concretos a numeroEntero y numeroFraccionario. Para declarar el constructor haramos: //Dentro de MiObjeto.h, a continuacin de @interface MiObjeto: NSObject {} -(MiObjeto*) init; -(MiObjeto*) initConNumeroEntero: (int) entero yNumeroFraccionario: (float) fraccion; // Dentro de MiObjeto.m, siempre dentro de @implementation y @end -(MiObjeto*) init { self = [super init]; if (self) { numeroEntero = 100; numeroFraccionario = 99.9999; }

return self; } // Otro constructor, donde definimos de forma explcita los valores de numeroEntero y numeroFraccionario: -(MiObjecto) initConNumeroEntero: (int) entero yNumeroFraccionario: (float) fraccin { self = [super init]; if (self) { [setNumeroEntero: entero]; [setNumeroFraccionario: fraccion]; } return self; } Con estos nuevos constructores, podramos inicializar los objetos as en main.m: int main( int numeroArgumentos, const char* argumentos) { // Inicializamos usando el NUEVO constructor por defecto, por lo que numeroEntero valdr 100 en miObjeto1 y numeroFraccionario valdr 99.999 MiObjeto* miObjeto1 = [[MiObjeto alloc] init]; // Inicializamos miObjeto2 usando el otro constructor, por lo que numeroEntero en miObjeto2 valdr 10, y numeroFraccionario valdr 9.9 MiObjeto* miObjeto2 = [[MiObjecto alloc] initConNumeroEntero:10 yNumeroFraccionario:9.9]; return 0; }

Acceso pblico, protegido y privado


Para declarar el tipo de acceso a variables y mtodos de un objeto, se declara en el archivo .h. Si no se especifica, el acceso por defecto es protected (nicamente accesible por la clase y subclases derivadas de sta). Supongamos que tenemos una clase DatosCliente, derivada de NSObject.

// Archivo DatosCliente.h #import <Foundation/NSObject.h> @interface DatosCliente : NSObject { @public // Todas las variables escritas a continuacin tienen acceso pblico int numeroDeCliente; int telefono; float saldo; @private // Todas las variables escritas a continuacin tienen acceso privado int dni; NSString* nombre; NSString* apellido; NSString* direccion; } // Archivo DatosCliente.m @implementation DatosCliente // No hay funciones que declarar @end // Archivo main.m #import DatosCliente.h int main(void) { DatosCliente* cliente = [[DatosCliente alloc] init]; // Accedemos directamente a la variable telfono, puesto que es pblica cliente->telefono = 1004; // Intentamos acceder a la variable dni, dar un error al compilar puesto que es privada cliente->dni = 0; return 0; }

Acceso a nivel de clase:

Habamos mencionado antes que existen dos tipos de mtodos, los precedidos por el signo menos y los precedidos por signo ms. Los mtodos con signo ms permiten que se pueda acceder a ellos sin necesidad de tener un objeto creado, de forma similar a como podemos acceder a funciones en C. El nico inconveniente es que, al ser de carcter global, lgicamente no se puede acceder a mtodos ni variables a nivel de instancia. Sin embargo s se pueden manipular objetos que se le pasen como argumentos a la funcin. Un ejemplo: // Archivo ObjetoEstatico.h #import <Foundation/NSObject.h> @interface ObjetoEstatico : NSObject +(void) setDatosCliente: (DatosCliente*) cliente; @end // Archivo ObjetoEstatico.m #import ObjetoEstatico.h #import DatosCliente.h @implementation ObjetoEstatico +(void) setDatosCliente: (DatosCliente*) cliente { // Accedemos a la variable pblica telfono del puntero a DatosCliente que recibe la funcin. cliente->telefono = 1004; } @end // Archivo main.m #import ObjetoEstatico.h #import <stdio.h> int main(void) { DatosCliente* miCliente = [[DatosCliente alloc] init]; [ObjetoEstatico setDatosCliente: miCliente]; printf(El telefono del cliente es %d\n, miCliente->telefono); [miCliente release]; return 0; } En particular, este tipo de mtodos lo utiliza Objective-C para llevar un contador del nmero de instancias que existe de un objeto. Cuando se crea un objeto el contador de instancias se incrementa en 1. Cuando el contador llega a cero, se desaloja completamente el objeto de la memoria.

El tipo de dato id
En Objective-C existe un tipo de dato llamado id, que es similar a un puntero a void en C/C++. La principal diferencia con C++ (y Java) es que al llamar a un mtodo de una id de un objeto en particular no es necesario saber el tipo de objeto en el que se est llamando al mtodo; simplemente debe existir el mtodo en dicho objeto. Esto se denomina message passing en Objective-C. Veamos ms en profundidad cmo funciona. Supongamos que tenemos dos objetos, de tipo MiObjetoUno yMiObjetoDos respectivamente, ambos con el mtodo: (void) inicializaVariable1: (int) var1 variable2: (int) var2 yVariable3: (int) var3; Supongamos que los mtodos funcionan de forma completamente distinta entre ambos objetos, pero la declaracin del mtodo es la misma para ambas clases. Para acceder a dicho mtodo en MiObjetoUno, usando el mtodo que hemos hecho hasta ahora, haramos: MiObjetoUno* obj1 = [[MiObjetoUno alloc] init]; [obj1 inicializaVariable1: 10 variable2: 20 yVariable3: 30]; De forma anloga, para MiObjetoDos sera: MiObjetoDos* obj2 = [[MiObjetoDos alloc] init]; [obj2 inicializaVariable1: 10 variable2: 20 yVariable3: 30]; Si utilizramos id, entonces simplemente bastara hacer: MiObjetoUno* obj1 = [[MiObjetoUno alloc] init]; MiObjetoDos* obj2 = [[MiObjetoDos alloc] init]; id ID = obj1; [ID inicializaVariable1: 10 variable2: 20 yVariable3: 30]; ID = obj2; [ID inicializaVariable1: 10 variable2: 20 yVariable3: 30];

Como podemos ver, id no es ni un objeto tipo MiObjetoUno, ni un objeto tipo MiObjetoDos. Es, como decamos antes, similar a un (void*), con la ventaja de que permite llamar a mtodos de objetos sin conocer el tipo de objeto que es; simplemente basta con saber que el objeto perteneciente a esa id que estamos manipulando tiene dicho mtodo.

Herencia entre clases


La herencia en Objective-C es similar a como funciona en Java y en C++. Un objeto solo puede descender de una clase (solo puede tener un padre), mtodos/variables pblicos son accesibles desde cualquier sitio, mtodos protegidos son accesibles por la clase que los declara y sus subclases, mtodos privados son nicamente accesibles por la clase que los declara. Para re-implementar mtodos protegidos/pblicos por subclases simplemente es necesario rescribir el mtodo en cuestin. Variables y mtodos privados, como ya hemos comentado, son accesibles nicamente por la clase que los declara; las clases que los heredan no tienen acceso a ellos.

Protocol
Los protocolos (protocol) en Objective C funcionan igual que las interfaces en Java, o las clases virtuales en C++. Los protocolos se declaran en un archivo .h y nicamente muestran la cabecera de las funciones que los objetos que usan dicho protocolo deben implementar. La nomenclatura del protocolo es: // Archivo MiPrimerProtocolo.h @protocol MiPrimerProtocolo -(void) print @end // Archivo MiObjeto.h, modificado para que tenga el protocolo #import <Foundation/NSObject.h> #import MiPrimerProtocolo.h

#import <stdio.h> @interface MiObjeto : NSObject <MiPrimerProtocolo> { // Atributo de tipo entero int numeroEntero; // Atributo de tipo float float numeroFraccionario; } // Mtodo para asignar un valor al atributo numeroEntero -(void) setNumeroEntero: (int) numero; // Mtodo para asignar un valor al atributo numeroFraccionario -(void) setNumeroFraccionario: (float) numero; // Mtodo para mostrar en pantalla el valor de numeroEntero -(void) printNumeroEntero; // Mtodo para mostrar en pantalla el valor de numeroFraccionario -(void) printNumeroFraccionario; // Mtodo que devuelve el valor del atributo numeroEntero -(int) getNumeroEntero; // Mtodo que devuelve el valor del atributo numeroFraccionario -(float) getNumeroFraccionario; // Declaro el mtodo print del protocolo -(void) print; @end // Archivo MiObjeto.m, modificado para que tenga la implementacin de print #import MiObjeto.h #import <stdio.h> @implementation MiObjeto -(void) setNumeroEntero:

(int) numero {

// Asignamos a nuestra variable numeroEntero el valor de numero numeroEntero = numero; } -(void) setNumeroFraccionario: (float) numero {

//Asignamos a nuestra variable numeroFraccionario el valor de numero numeroFraccionario = numero; } -(void) printNumeroEntero { // Mostramos por pantalla el valor de numeroEntero printf(Numero entero: %d, numeroEntero); } -(void) printNumeroFraccionario { // Mostramos por pantalla el valor de numeroFraccionario printf(Numero fraccionario: %d, numeroFraccionario); } -(int) getNumeroEntero { return numeroEntero; } -(float) getNumeroFraccionario { return numeroFraccionario; } -(void) print { NSLog(@Soy un objeto tipo MiObjeto que implementa MiPrimerProtocolo!\n); } @end // Archivo main.m

int main(void) { MiObjeto* objeto = [[MiObjeto alloc] init]; id <MiPrimerProtocolo> esteObjetoPuedeHacerPrint = objeto; // Llamamos al mtodo print de esteObjetoPuedeHacerPrint: [esteObjetoPuedeHacerPrint print]; [release objeto] return 0; }

Manejo de memoria
Esta es quizs la parte ms importante del tutorial. Hasta ahora todos los objetos que hemos creado eran muy sencillos, puesto que tenan variables que eran de tipo fundamental, con la excepcin del objeto DatosCliente. Objective C es una extensin de C (o un superconjunto de C), es decir que se puede intercalar cdigo en C y Objective C. Sin embargo para la reserva y liberacin de memoria, o usamos C, o usamos Objective C; no se puede hacer un alloc y luego un free(), por ejemplo, del mismo modo que en C++ no se puede usar new para reservar memoria y luego free() para ese bloque de memoria, o no se puede hacer un malloc() para reservar y luego usar delete para liberar. Bien; para Objective C tenemos 3 palabras clave: alloc, retain y release. La palabra alloc la hemos estado utilizando constantemente y, como su nombre indica, aloja memoria para un objeto que vayamos a crear. La palabra retain indica que queremos RETENER una instancia en memoria. Pero, por qu querramos hacer tal cosa?.Como ya hemos comentado antes, todos las clases derivadas de NSObject tienen un contador de instancias que funciona a nivel de clase (es, digamos, una variable de tipo global). Podemos ver dicho contador usando el mtodo de NSObject [retainCount]. Este contador sirve para que al llegar a cero, se desaloje completamente de la memoria el objeto en cuestin. La palabra clave retain va a incrementar en uno el contador de instancias aunque no se aloje memoria extra para un objeto. Ahora veremos por qu. Cada vez que se hace un [alloc] se incrementa el contador, esto es evidente. Sin embargo, vayamos a un caso prctico ms complejo. Supongamos que tenemos un objeto tipo SuperObjeto que tiene, a su vez, una variable llamada dato, que es un objeto de tipo MiniObjeto. Supongamos adems que SuperObjeto tiene un mtodo de este tipo: -(void) setDato: (MiniObjeto*) nuevoDato; Al crear una nueva instancia de SuperObjeto en la funcin main(), haramos la inicializacin como siempre: SuperObjeto* superObjeto = [[SuperObjeto alloc] init];

Supongamos, adems, que el mtodo init de SuperObjeto NO inicializa la variable dato. En este punto del programa tendramos cero instancias de MiniObjeto porque todava no hemos creado ninguna. Adems, superObjeto->dato sera por tanto nil (NULL en C/C++). Vamos a ver qu ocurre al asignarle un valor usando setDato. Usemos este programa de ejemplo: int main(void) { SuperObjeto* superObjeto = [[SuperObjeto alloc] init]; // En esta lnea, el contador de instancias de MiniObjeto es CERO. MiniObjeto* miDato1 = [[MiniObjeto alloc] init]; // Ahora el contador de instancias es UNO. MiniObjeto* miDato2 = [[MiniObjeto alloc] init]; // Ahora el contador de instancias es DOS. [superObjeto setDato: miDato1]; // Y ahora cunto es el contador de instancias de MiniObjeto?? [miDato1 release]; [miDato2 release]; [superObjeto release]; return 0; } La pregunta de Y ahora cunto es el contador de instancias de MiniObjeto?? tiene trampa: depende de cmo hayamos implementado setDato. Puesto que queremos un programa que use el mnimo posible de memoria (y, de paso, que no tenga fugas), vamos a hacerlo de forma correcta: borraremos de memoria el dato que tenamos y le asignaremos el nuevo objeto que recibe como argumento. // En SuperObjeto.m @implementation SuperObjeto { -(void) setDato: (MiniObjeto*) nuevoDato { // Nos est llegando un MiniObjeto*, es decir que AL MENOS existe una instancia de MiniObjeto. Supongamos que el contador es exactamente uno. // Al mismo tiempo, queremos machacar el valor antiguo de dato, por lo que tendramos que hacer un [release] de dato.

// Pero como ya habamos comentado, un [release] va a decrementar en 1 el nmero de instancias. Si nicamente tenemos una instancia (la del puntero que le est llegando a esta funcin), si hacemos un [release] prematuro dejaramos a cero el contador y se llamara a la funcin interna [dealloc], cosa que NO queremos que ocurra. // Por este motivo debemos hacer un [retain] del nuevo valor que nos est llegando primero. [nuevoDato retain]; // Haciendo un retain incrementamos en uno el contador de instancias. Si antes era uno, ahora es DOS. [dato release]; // En este supuesto, dato NO estaba inicializado por lo que apuntaba a nil. Hacer [nil release] no hace nada, por lo que ahora mismo hemos garantizado que si dato tena algn valor, este ha sido destruido, y si NO tena ningn valor, no ocurrir nada. // Al mismo tiempo, al hacer un release, el contador se decrementa. Siguiendo con nuestro supuesto, el contador pasa a valer UNO otra vez. dato = nuevoDato; // Ya est: nuestro puntero dato apunta ahora a nuevoDato. Nuestro contador de instancias marca 1, y no tendremos fugas de memoria siempre y cuando hagamos el desalojo correcto en el [dealloc] de nuestro objeto, que es precisamente lo que viene a continuacin. } @end Volviendo a la pregunta de antes: // Y ahora cunto es el contador de instancias de MiniObjeto?? Segn nuestra implementacin, sigue siendo DOS!

Dealloc

Acabamos de ver como funciona alloc, retainy release. Sin embargo, para terminar el cuadro necesitamos ver el destructor de objetos propiamente, la funcin dealloc. Para objetos ms complejos como el caso anterior, en general tendremos que tener cuidado de cundo y cmo desalojamos memoria. En particular al destruir un objeto, al igual que en C++, es necesario destruir los objetos de los que est compuesta nuestra clase. Esto evita que haya fugas de memoria de punteros que no han sido correctamente liberados, y es el mismo problema que hay en C y C++. La funcin dealloc es heredada de NSObject y es pblica, por lo que la podemos re-implementar. Para ello, en nuestra clase SuperObjeto haramos: // Archivo SuperObjeto.m -(void) dealloc { // Liberamos nuestro objeto. Si ya est liberado, lo que har es [nil release] por lo que no hay problema. [data release]; // La llamada a dealloc de la superclase siempre va al final. [super dealloc]; } El mtodo dealloc se llama automticamente cuando no quedan instancias del objeto, y NO debe llamarse de forma explcita nunca. Al reimplementar dealloc en una clase derivada de otra, la llamada al mtodo de la superclase se debe hacer AL FINAL de la reimplementacin, como se muestra en el ejemplo de arriba.

Enlaces de inters
Este tutorial es una buena forma de iniciarse en Objective C si se poseen conocimientos de C y C++, pero para aquellos que estn familiarizados nicamente con Java (o C# incluso) es francamente escaso en cuanto a cmo funciona el manejo de memoria, en qu consiste un puntero, y otras dudas razonables que puedan surgir. El artculo Advanced Memory Management de la pgina oficial de Apple cubre con ms detalle algunas de estas preguntas (en ingls). Otro enlace de inters, tambin en ingls, es Learning Objective-C: A Primer.

You might also like