Está en la página 1de 59

BecomeAnXcoder-Español 19/05/10 20:25

BecomeAnXcoder-Español
Un libro gratis para comenzar con el uso de Cocoa y Objective-C

Por favor Donar! Si valora nuestro trabajo, por favor, tómese un minuto para enviar una donación.

Bert Altenburg, autor de AppleScript for Absolute Starters, en cooperación con Alex Clarke y Philippe Mougin, ha publicado un
libro para los recién llegados a la programación utilizando Cocoa, Objective-C y Xcode.

Este tutorial está escrito para los no programadores, y tiene por objeto nivelar la curva de aprendizaje tanto como sea posible.
En la mejor tradición, BecomeAnXcoder se libera como un folleto gratuito en formato pdf bajo una licencia CC Atribución.
También está disponible en línea, basta con seguir los enlaces de abajo.

BecomeAnXcoder ha sido descargado más de 110000 veces desde mayo de 2006. Si desea ayudar a crear una traducción al
alemán, francés, español, italiano, portugués o cualquier otro idioma, por favor póngase en contacto conmigo: alex a cocoalab
dot com.

Atención: BecomeAnXcoder chino, árabe y japonés fueron escritos para OS X 10,4 Tiger, por lo que actualmente contienen
información obsoleta. El libro de Inglés ha sido actualizado para Xcode 3 y OS X Leopard 10.5 .

La versión en línea del libro es siempre la más actualizada. De vez en cuando voy a condensar todos los cambios a la versión en
Inglés de la versión en línea y crear un nuevo pdf. Las traducciones son mantenidas por voluntarios independientes y por lo
tanto no pueden estar en sintonía con la actual versión en Inglés.

Descargas PDF
NUEVO! Become An Xcoder (Ingles - Leopard) (2MB PDF file)
Become An Xcoder (Ingles - Tiger) (2MB PDF file)
Become An Xcoder (Japones) (2.3MB PDF file)
Become An Xcoder (Chino Simplificado) (1.2MB PDF file)
Become An Xcoder (Chino Tradicional) (4.5MB PDF file)
Become An Xcoder (Arabico) (1.5MB PDF file)

Online Book

About
Este libro tiene como propósito introducirle a los conceptos fundamentales de la programación
de el sistema Mac utilizando Xcode y Objective-C.

No se requiere experiencia previa en programación.

Introducción
Apple te ofrece todas las herramientas necesarias para desarrollar aplicaciones basadas en Cocoa, de forma gratuita. Este
conjunto de herramientas, conocido con el nombre de Xcode, viene incluido con Mac OS X, o puedes bajarlo de la sección de
desarrolladores en el sitio web de Apple.
Existen varios buenos libros sobre programación para Mac, pero asumen que ya tienes experiencia en programación. Este libro
no. Se enseñan los conceptos básicos de programación, en particular con Objective-C, usando Xcode. Después de unos 5
capítulos, serás capaz de crear un programa básico, sin una interfaz gráfica de usuario (GUI). Después de unos capítulos más,
sabrás cómo crear programas sencillos con un GUI. Cuando hayas terminado de leer este folleto, estarás listo para utilizar libros
más avanzados. Tendrá que estudiar esos libros también, porque hay mucho más que aprender. Por ahora, sin embargo, no te
preocupes porque este libro toma las cosas con calma.

Cómo usar este libro


Como podrás observar, algunos párrafos se muestran en un recuadro como el siguiente:

puntos técnicos

http://www.cocoalab.com/?q=book/export/html/60 Página 1 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Te sugerimos leer cada capítulo dos veces (por lo menos). La primera vez pasa la caja de texto. La segunda vez que leas los
capítulos incluye la caja de texto. Vas a ensayar en la práctica lo que has aprendido y aprenderás algunos puntos técnicos
interesantes que hubieran sido distracciones la primera vez. Al utilizar el libro de esta manera, lograrás que la inevitable curva
de aprendizaje sea una suave pendiente.
Este libro contiene docenas de ejemplos, que constan de una o más líneas de código de programación. Para asegurarse de que
asocies una explicación a su respectivo ejemplo, cada ejemplo tiene la etiqueta de un número colocado entre corchetes, de esta
manera: [1]. La mayoría de los ejemplos tienen dos o más líneas de código. A veces, un segundo número se utiliza para referirse
a una determinada línea. Por ejemplo, [1.1] se refiere a la primera línea del ejemplo [1]. En los fragmentos largos de código,
ponemos la referencia después de una línea de código, de esta manera:

//[1]
volumen = base * altura; // [1.1]

La programación no es un trabajo simple . Se requiere un poco de perseverancia y que tú mismo trates de hacer todas las cosas
que se enseñan en este libro. No se puede aprender a tocar el piano o conducir un coche exclusivamente por la lectura de libros.
Lo mismo vale para aprender a programar. Este libro está en un formato electrónico, por lo que no tienes ninguna excusa para
utilizar Xcode con frecuencia. Por lo tanto, a partir del capítulo 5, te sugerimos que vayas a través de cada capítulo en tres
ocasiones. La segunda vez, prueba los ejemplos y haz pequeñas modificaciones al código para explorar cómo funcionan las
cosas.

00: Antes de empezar


Escribimos este libro para usted. Como es gratis, por favor permítame decir un par de palabras sobre la promoción de la Mac a
cambio. Cada usuario de Macintosh puede ayudar a promover su plataforma preferida con un poco esfuerzo. Aquí es cómo.

Cuanto más eficiente con la Mac sea usted, más fácil es llevar a otras personas a considerar una Mac. Por lo tanto, tratar de estar
al día visitando sitios web orientados a la Mac y leer revistas de Mac. Por supuesto, el aprendizaje de Objective-C o
AppleScript y ponerlos en uso es bueno tambien. Para las empresas, el uso de AppleScript puede ahorrar toneladas de dinero y
tiempo. Echa un vistazo al folleto gratis de Bert, AppleScript Absolutos para Principiantes, disponible en:

http://www.macscripter.net/books

Muestrale al mundo que no todo el mundo está usando una PC, haciendo la Macintosh más visible. El uso de una camiseta en
público con el logo de Mac es una manera, pero hay otras maneras, puede hacer que el Mac sea más visibles dentro de su hogar.
Si ejecuta Activity Monitor (en la carpeta Utilidades, que se encuentra en la carpeta de Aplicaciones de tu Mac), te darás cuenta
de que tu Mac utiliza todo su poder de procesamiento sólo de vez en cuando. Los científicos han puesto en marcha varios
proyectos de informática distribuida (DC) , como el Folding@home o SETI@home, que aprovechar esta potencia de
procesamiento no utilizada, por lo general en pro del bien común.

Usted descarga un pequeño programa gratuito, llamado DC client, y empezara a procesar unidades de trabajo. Estos clientes DC
correr con menor nivel de prioridad. Si estás usando un programa en tu Mac y las necesidades del programa requieren plena
potencia de procesamiento, el DC client inmediatamente toma menor prioridad. Así, usted no notará que está funcionando.
¿Cómo ayuda esto a las Mac? Bueno, la mayoría de los proyectos DC mantienen rankings en sus sitios web de las unidades
procesadas hasta la fecha. Si se inscribe en un equipo Mac (reconocerá sus nombre en los rankings), puede ayudar al equipo
Mac de su elección para ascender en la clasificación. Así, los usuarios de otras plataformas de ordenador veran que tan bien las
Macs están haciendo. Hay DC clients que se concentran en varios temas, como matemáticas, curar enfermedades y mucho más.
Para elegir un proyecto DC que te gusta, echa un vistazo a:

http://distributedcomputing.info/projects.html

Un problema con esta sugerencia: Se puede llegar a ser adicto!

Asegúrese de que la plataforma Macintosh tiene el mejor software. No, no sólo mediante la creación de programas propios.
Haga un hábito de dar (cortés) retroalimentación a los desarrolladores de programas que usted utiliza. Incluso si trató una pieza
de software y no le gusto, expliquele al desarrollador por qué. Asegúrese de informar sobre errores y proporcione una
descripción exacta como sea posible de las acciones que realizó cuando se experimentó el error.
Pagar por el software que usted utiliza. Mientras el mercado de software para Macintosh sea viable, los desarrolladores seguirán
proveyendo buen software.

Póngase en contacto con al menos 3 usuarios de Macintosh que podrían estar interesados en programación, digales acerca de
este libro y dónde encontrarlo. O asesorelos sobre los 4 puntos mencionados arriba.

OK, mientras el DC client termina de descargar en el fondo, vamos a empezar!

http://www.cocoalab.com/?q=book/export/html/60 Página 2 de 59
BecomeAnXcoder-Español 19/05/10 20:25

01: Un programa es una serie de instrucciones


Presentación
Para conducir un automóvil, tienes que aprender a controlar varias cosas a la vez. La programación también requiere que
mantengas un montón de cosas en mente, o tu programa romperá. Mientras que al menos ya conocías el interior de un coche
antes de aprender a conducir, no tendrás esa ventaja cuando trates de aprender a programar con Xcode. Para no abrumarte,
dejamos el entorno de programación para un capítulo posterior. En primer lugar, vamos a hacer que te sientas cómodo con
algunos conceptos de Objective-C, empezando por la matemática básica.

En la escuela primaria había que hacer cálculos, rellenando los puntos:

2 + 6 = ……..
…….. = 3 * 4 (el asterisco * es la forma estándar para representar la multiplicación en los teclados de ordenador)

En la escuela secundaria, los puntos pasaron de moda y unas variables llamadas 'x' e 'y' (y una nueva palabra: "álgebra") fueron
la gran sensación. Mirando hacia atrás, puede que te preguntes por qué nos hemos sentido tan intimidados en su momento por
este pequeño cambio en la notación.

2 + 6 = x
y = 3 * 4

Variables
Objective-C también utiliza variables. Las variables no son nada más que nombres para referirse a unos datos concretos, como
por ejemplo un número. Aquí tenemos una sentencia Objective-C, es decir, una línea de código, en la que asignamos un valor a
una variable.
//[1]
x = 4;

El punto y coma
Se le ha asignado el valor 4 a la variable x . Te habrás dado cuenta de que hay un punto y coma al final de la instrucción. Esto se
debe a que se requiere que todas las instrucciones terminen en punto y coma. ¿Por qué? Bien, el trozo de código que hay en el
ejemplo [1] puede parecerte sencillo, pero un ordenador no es capaz de comprenderlo. Se necesita un programa especial,
llamado compilador, para convertir ese texto en una secuencia de instrucciones que él sí sea capaz de entender y ejecutar. Leer y
entender nuestro idioma puede ser muy difícil para un compilador así que debemos darle algunas pistas, por ejemplo: indicarle
dónde termina cada sentencia; y eso es lo que hacemos con el punto y coma.

Si te olvidas el punto y coma en tu código, éste no se podrá compilar, es decir, no se va a poder convertir en un programa que tu
Mac pueda ejecutar. No te preocupes ahora de eso, pues el compilador se quejará si hay algún problema y, como veremos en un
capítulo posterior, intentará ayudarte a encontrar lo que esté mal.

Dar nombres a las variables


Mientras que los nombres de las variables no tienen una importancia especial para el compilador, el utilizar nombres
descriptivos sí que nos puede facilitar la lectura del programa y hacerlo más comprensible. Ten esto en cuenta para cuando
tengas que buscar errores en tu código.

Por tradición se llaman "bugs" (bichos) a los errores de los programas. A la búsqueda y reparación de bugs se le llama
debugging (en español solemos decir depuración).

Por tanto, en programas reales evitaremos usar nombres de variables no descriptivos tales como x . Por ejemplo, el nombre de la
variable en la que almacenaríamos el ancho de un dibujo sería anchoDibujo [2].
//[2]
anchoDibujo = 8;

Ahora que sabes que para el compilador es un gran problema que te olvides del punto y coma, comprenderás que en la
programación hay que prestar atención a los detalles. Uno de esos detalles es que el código es sensible a
mayúsculas/minúsculas. Es decir, la variable anchoDibujo no es la misma que anchoDIBUJO ni que AnchoDibujo . La

http://www.cocoalab.com/?q=book/export/html/60 Página 3 de 59
BecomeAnXcoder-Español 19/05/10 20:25

convención que vamos a seguir para los nombres de variables es unir varias palabras, la primera iniciada por minúsculas y el
resto por mayúsculas, tal como has visto en el ejemplo [2]. A este estilo se le suele llamar camelCase (se llama así por las
jorobas del camello, en inglés camel. Cada mayúscula es una joroba). Te será conveniente seguir este esquema para reducir las
posibilidades de cometer errores con los nombres de variables.

Ten en cuenta que los nombres de variables consisten en una sola palabra, en el sentido de que no hay espacios en el nombre.

Tienes total libertad para elegir el nombre de tus variables, pero hay una serie de reglas que debes seguir: la primera es que no
puede ser el nombre de una palabra reservada de Objective-C (palabras que tienen un significado especial para Objective-C). Si
tus variables están compuestas al menos de dos palabras unidas, como por ejemplo anchoDibujo , no vas a tener problema.
Para facilitar la lectura se recomienda poner en mayúscula la inicial de cada palabra excepto la primera, tal como hemos visto.
Sigue este esquema para evitar bugs en tus programas.

Si no te importa aprender un par de reglas más, sigue leyendo. También se permite el uso de dígitos además de letras, pero no
puedes usar un dígito al comienzo del nombre. También se permite el guión bajo: "_". Vamos a ver ejemplos de nombres de
variables.

Nombres válidos de variables:

puerta8k
pu3rta
puer_ta

Nombres no permitidos:

puerta 8 (porque contiene un espacio)


8puerta (porque empieza por un dígito)

Nombres válidos pero no recomendados:

Puerta8 (porque empieza por mayúscula)

Uso de variables en cálculos


Ahora que sabemos como asignar un valor a una variable, podemos hacer cálculos. Echemos un vistazo al código para calcular
la superficie de un dibujo [3].
//[3]
anchoDibujo=8;
altoDibujo=6;
areaDibujo=anchoDibujo*altoDibujo;

Sorprendentemente, al compilador no le importan los espacios (con la excepción, como ya sabemos, de que están prohibidos en
los nombres de variables), así que podemos usar todos los que queramos para facilitar la lectura de nuestro código.

//[4]
anchoDibujo = 8;
altoDibujo = 6;
areaDibujo = anchoDibujo * altoDibujo;

Y en un arranque de generosidad, el compilador también nos permite introducir saltos de línea en medio de las instrucciones ¿te
imaginas por qué? Pues porque, si recuerdas lo que vimos un poco más arriba, él va a interpretar todo como una sola instrucción
hasta que encuentre el punto y coma (el indicador de fin de instrucción). Podemos usar esta característica para facilitar la lectura
en líneas excesivamente largas. Así que lo siguiente también sería válido para el compilador (pero también bastante incómodo
de leer):

anchoDibujo =
8;
altoDibujo
= 6;
areaDibujo =
anchoDibujo
*
altoDibujo;

Enteros y fraccionarios
http://www.cocoalab.com/?q=book/export/html/60 Página 4 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Echemos un vistazo al ejemplo [5], especialmente a las dos primeras sentencias.

//[5]
anchoDibujo = 8;
altoDibujo = 4.5;
areaDibujo = anchoDibujo * altoDibujo;

Se pueden distinguir en general dos tipos de números: enteros y fraccionarios. Puedes ver un ejemplo de cada en [5.1] y [5.2]
respectivamente. Los enteros se usan para contar, que es algo que haremos cuando queramos realizar una serie de instrucciones
un número determinado de veces (ver capítulo 7). Los números fraccionarios los usamos, por ejemplo, con los precios.

Importante: Según el país, se usa como carácter separador de la parte decimal el punto "." o la coma ",". En Objective-C
debemos emplear obligatoriamente siempre el punto.

El código del ejemplo [5] no funcionaría. El problema es que el compilador necesita que le indiques previamente el nombre de
las variables que vas a usar en tu programa y también qué tipo de dato va a contener cada una. Eso es lo que llamamos "declarar
una variable".

//[6]
int anchoDibujo; // [6.1]
float altoDibujo, areaDibujo; // [6.2]
anchoDibujo = 8;
altoDibujo = 4.5;
areaDibujo = anchoDibujo * altoDibujo;

En la línea [6.1], int indica que la variable anchoDibujo contiene un número entero. En la siguiente línea [6.2] declaramos
dos variables con una sola instrucción, separando sus nombres con coma. En la sentencia también se indica que son de tipo
float , lo que quiere decir que van a ser números con una parte fraccionaria. Llegados a este punto, parece que no tiene sentido
que la variable anchoDibujo sea de tipo diferente a las otra dos. Pero lo que sabes es que si multiplicas un int por un float
el resultado del cálculo es un float , que es la razón por la que deberías declarar la variable areaDibujo como float [6.2].

¿Por qué quiere el compilador conocer si una variable representa a un número entero o a uno fraccionario? Bien, un programa
usa parte de la memoria del ordenador y el compilador reserva espacio para cada variable que se declara, pero necesita saber el
tipo, ya que cada tipo requiere una cantidad distinta y también se representa de forma distinta en la memoria del ordenador.

¿Y si necesitamos trabajar con números muy grandes o con gran precisión de decimales? ¿Van a poder representarse en los
tipos que conocemos hasta ahora ( int y float )? Bien, esta pregunta tiene dos respuestas: en primer lugar, existen otros tipos
de datos para enteros más grandes ( long ) y para fraccionarios de más precisión ( double ). Pero incluso estos tipos de dato
podrían no ser suficiente, lo que nos lleva a la segunda respuesta: como programador, parte de tu trabajo es estar atento a los
posibles problemas. Pero eso no es un asunto para discutir en el primer capítulo de un libro de introducción.

Por cierto, los tipos que hemos visto pueden almacenar también números negativos. Si sabes que el valor de tu variable nunca
va a ser negativo puedes restringir el rango de valores.

//[7]
unsigned int cajasDisponibles;

No tiene sentido que el número de cajas disponibles en el almacén sea negativo, así que en este caso podríamos usar unsigned
int . El tipo unsigned int representa un número entero mayor o igual a cero.

Declarar variables
Es posible declarar una variable y asignarle un valor de una vez [8].

//[8]
int x = 10;
float y= 3.5, z = 42;

Esto te ahorra algo de tecleo.

Tipos de datos
Como ya hemos visto, los datos almacenados en variables pueden ser de varios tipos específicos, por ejemplo int o float .

En Objective-C, a los tipos de dato como esos se les llama también tipos escalares. A continuación mostramos una lista con los
tipos de dato escalares más comunes de Objective-C:

http://www.cocoalab.com/?q=book/export/html/60 Página 5 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Nombre Tipo Ejemplo


void Vacío Nada
int Número entero ...-1, 0, 1, 2...
unsigned Número entero positivo 0, 1, 2...
float Número fraccionario -0.333, 0.5, 1.223, 202.85556
double Número fraccionario de doble precisión 0.52525252333234093890324592793021
char Carácter hola
BOOL Boolean 0, 1; TRUE, FALSE; YES, NO.

Operaciones matemáticas
En los ejemplos previos hemos realizado una multiplicación. Se usan los siguientes símbolos, conocidos oficialmente como
"operadores", para realizar cálculos matemáticos básicos.
+ suma
- resta
/ división
* multiplicación

Aparte de estos operadores, si echamos un vistazo al código de un programa en Objective-C, podemos encontrarnos con un par
de curiosidades, quizá porque los programadores son unos mecanógrafos perezosos.

En lugar de escribir x = x + 1; , con frecuencia los programadores recurren a cosas como [9] y [10]

//[9]
x++;

//[10]
++x;

En cualquiera de los dos casos, lo que significa es: incrementa en 1 el valor de x . En algunas circunstancias es importante situar
el ++ antes o después del nombre de la variable. Fíjate en estos ejemplos [11] y [12].

//[11]
x = 10;
y = 2 * (x++);
// "x" tiene aquí el valor 11, pero se le asignó DESPUES de realizar el cálculo
// por tanto "y" tiene el valor 20

//[12]
x = 10;
y = 2 * (++x);
// "x" también vale ahora 11, pero su valor se asignó ANTES de hacer el cálculo
// así que "y" vale 22

Si usamos el ++ antes del nombre de la variable, se incrementará su valor antes de emplear la variable en el cálculo en el que
esté envuelta. Si usamos ++ después del nombre de la variable, se incrementará su valor después de utilizarse en el cálculo en el
que esté envuelta. El código de [12] es equivalente al de [13].

//[13]
x = 10;
x++; // [13.2]
y = 2 * x;
// Como el incremento de x en la línea [13.2] no está envuelto en ninguna
// operación, en este caso sería lo mismo usar ++x que x++

Con esto se unen dos sentencias en una, pero quizá pueda hacer un poco más difícil de entender tu programa. Es correcto
emplearlo pero ten en cuenta que puede estar acechando un bug por ahí.

http://www.cocoalab.com/?q=book/export/html/60 Página 6 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Paréntesis
Seguro que ya lo sabes, pero los paréntesis se pueden utilizar para indicar el orden en el que queremos que se realicen las
operaciones. La multiplicación y división tienen precedencia sobre la suma y la resta, así que, por ejemplo, 2 * 3 + 4 es igual a
10. Usando paréntesis podemos forzar a que se realice antes la suma que la multiplicación: 2 * (3 + 4) es igual a 14.

División
La división requiere un poco de atención, ya que tiene un comportamiento distinto según usemos enteros o fraccionarios. Echa
un vistazo a los ejemplos [14] y [15].
//[14]
int x = 5, y = 12, ratio;
ratio = y / x;

//[15]
float x = 5, y = 12, ratio;
ratio = y / x;

En el primer caso [14], el resultado es 2 ¿Por qué? Al ser enteros el dividendo y el divisor, el resultado también es un número
entero. En el segundo [15], el resultado es el que probablemente te esperas: 2,4

Booleanos
Un booleano (la palabra viene de George Boole, el matemático inventor de la lógica booleana) es un valor lógico verdadero o
falso. Se pueden considerar equivalentes el 1 como valor verdadero y el 0 como valor falso.

Verdadero Falso
1 0

Se emplean con frecuencia para determinar si se realiza o no una acción dependiendo del valor booleano de alguna variable o
función.

Resto (en inglés: modulus)


Probablemente no estés tan familiarizado con el operador % , que no tiene que ver con los porcentajes sino que calcula el resto de
la división entre el primer y el segundo operando (si el segundo operando es 0 , el comportamiento de % es indefinido).

//[16]
int x = 13, y = 5, resto;
resto = x % y;

La variable resto contendrá el valor 3 .

Más ejemplos de este operador:

21 % 7 es igual a 0
22 % 7 es igual a 1
23 % 7 es igual a 2
24 % 7 es igual a 3
27 % 7 es igual a 6
30 % 2 es igual a 0
31 % 2 es igual a 1
32 % 2 es igual a 0
33 % 2 es igual a 1
34 % 2 es igual a 0
50 % 9 es igual a 5
60 % 29 es igual a 2

Puede sernos útil en ocasiones, pero ten en cuenta que sólo funciona con enteros.

Uno de los usos más comunes del operador % es determinar si un número es par o impar. Si es par, su resto entre 2 es 0, si es
impar entonces será 1. Por ejemplo:

http://www.cocoalab.com/?q=book/export/html/60 Página 7 de 59
BecomeAnXcoder-Español 19/05/10 20:25

//[17]
int unNumero;
//Aquí escribiríamos código que asigna un valor a "unNumero"
if ((unNumero % 2) == 0) // [17.3]
{
NSLog(@"unNumero es par");
}
else
{
NSLog(@"unNumero es impar");
}

En la línea [17.3] se ha empleado un condicional, que verás en el capítulo 6. Podríamos traducir la instrucción como: "si el resto
de la división unNumero entre 2 es igual a 0, entonces …"

02: Sin comentarios? Inaceptable!


Introducción
Si utilizamos nombres de variables con sentido, haremos que nuestro código sea más legible y entendible [1].

//[1]
float anchoDelDibujo, altoDelDibujo, areaDelDibujo;
anchoDelDibujo = 8.0;
altoDelDibujo = 4.5;
areaDelDibujo = anchoDelDibujo * altoDelDibujo;

Hasta ahora nuestros ejemplos de código han sido de sólo unas pocas sentencias, pero incluso los programas más sencillos
pueden crecer rápidamente hasta cientos o miles de líneas. Cuando revises tu programa después de algunas semanas o meses
puede ser difícil recordar la razón por la que tomaste ciertas decisiones. Ahí es donde entran en acción los comentarios. Los
comentarios ayudarán a comprender rápidamente lo que hace cada parte de tu programa y por qué. Algunos programadores van
más allá y siempre comienzan a codificar cada clase como comentarios, con lo que se organizan mejor y evitan tener que
improvisar código posteriormente.

Recomendamos invertir tiempo en comentar el código. Podemos asegurarte que esa inversión será revertida con creces en el
futuro. También, si compartes tu código con alguien más, tus comentarios ayudarán a que se adapte a tus propias necesidades
más rápidamente.

Crear comentarios
Para indicar el comienzo de un comentario teclea dos barras.
// Esto es un comentario

En Xcode los comentarios se muestran en verde. Si el comentario es largo y ocupa varias líneas, enciérralo entre /* */ .

/* This is a comment
extending over two lines */

Comentar código
Hablaremos sobre la depuración dentro de poco, ya que Xcode tiene buenas herramientas para ello. Una de las formas de
depuración a la vieja usanza es comentar el código. Comentamos código envolviendo las instrucciones entre /* */ , de esta
forma deshabilitamos el código, impidiendo su ejecución y podemos comprobar si el resto funciona como esperábamos. Esto
puede ayudarnos a encontrar errores. Si, por ejemplo, la parte de código comentada asigna valores a una variable, podemos
añadir una línea de código temporal que asigne a esa variable un valor que nos sirva para comprobar el resto de nuestro código.

¿Por qué incluir comentarios?


No debemos desestimar la importancia de los comentarios. Frecuentemente es útil incluir explicaciones en nuestro idioma sobre
lo que hace una serie de instrucciones. Así no hay que estar deduciendo qué es lo que hace esa parte de código y podemos
darnos cuenta inmediatamente de si el problema tiene su origen o no en esa sección. Además podemos usar los comentarios
para explicar cosas difíciles o casi imposibles de deducir leyendo el código. Por ejemplo, si programas una función matemática

http://www.cocoalab.com/?q=book/export/html/60 Página 8 de 59
BecomeAnXcoder-Español 19/05/10 20:25

que encontraste detallada en un libro, podrías poner la referencia bibliográfica dentro de un comentario.

A veces es útil hacer los comentarios antes de escribir el código. Eso ayudará a estructurar tus pensamientos y como resultante
la programación será mas fluida.

Los ejemplos de código que encontrarás en este libro no contienen tantos comentarios como generalmente se deberían poner,
pero eso es porque ya se dan las explicaciones en el texto que los precede.

03: Funciones
Introducción
El trozo de código más largo que hemos visto hasta ahora tenía sólo cinco líneas. Los programas de varias miles de líneas
parecen quedarnos aún muy lejos, pero debido a la naturaleza de Objective-C, debemos discutir la forma de organizar los
programas en esta etapa temprana.

Si un programa consistiese en una sucesión larga y continua de instrucciones sería difícil encontrar y reparar errores. Además,
una serie concreta de instrucciones podría aparecer en varias partes de tu programa. Si hubiese en ellas algún error, deberías
arreglar el mismo error en varios lugares. Eso sería una pesadilla porque sería fácil olvidarse de uno (o varios). Por tanto, la
gente ha pensado una solución para organizar el código, facilitando la corrección de errores.

La solución a este problema es agrupar las instrucciones dependiendo de la tarea que realicen. Por ejemplo, tienes una serie de
instrucciones que calculan el área de un círculo. Una vez que has comprobado que esas instrucciones funcionan correctamente,
nunca tendrás que volver a ese código para examinar si hay algún error en él. El conjunto de instrucciones, llamado función
( function en inglés), tiene un nombre y puedes llamarlo por ese nombre cada vez que necesites que se ejecute ese código. Este
concepto de usar funciones es fundamental, de hecho siempre hay al menos una función en un programa: la función main() .
Esta función main() es la que busca el compilador para saber por donde debe empezar la ejecución del programa.

La función main()
Pasemos a estudiar la función main() con más detalle. [1]

//[1]
main()
{
// Cuerpo de la función main(). Escribe aquí tu código.
}

La sentencia [1.1] muestra el nombre de la función, en este caso "main", seguido de la apertura y cierre de paréntesis. Es
obligatorio que exista esta función main() , que por otro lado es una palabra reservada (lo que significa entre otras cosas que no
podemos usarla como nombre para nuestras variables). Cuando creemos nuestras funciones podremos darles el nombre que
queramos. Los paréntesis están ahí por una buena razón, pero la conoceremos más adelante en este capítulo. En las siguiente
líneas [1.3, 1.5], hay llaves. Debemos poner nuestro código entre esas llaves { } . Cualquier cosa entre las llaves es lo que
llamamos el cuerpo de la función. He copiado código del primer capítulo y lo he puesto aquí en donde corresponde [2].

//[2]
main()
{
// A continuación se declaran las variables
float anchoDelDibujo, altoDelDibujo, superficieDelDibujo;
// Asignamos un valor inicial a las variables
anchoDelDibujo = 8.0;
altoDelDibujo = 4.5;
// Aquí se realiza el cálculo
superficieDelDibujo = anchoDelDibujo * altoDelDibujo;
}

Nuestra primera función


Si escribimos todo nuestro código en el cuerpo de la función main() , eso nos llevaría al problema del código desestructurado y
difícil de depurar que queremos evitar. Así que escribamos otro programa, ahora con un poco de estructura. Además de la
función main() obligatoria crearemos una función calculaAreaDelCirculo() [3].

//[3]

http://www.cocoalab.com/?q=book/export/html/60 Página 9 de 59
BecomeAnXcoder-Español 19/05/10 20:25

main()
{
float anchoDelDibujo, altoDelDibujo, superficieDelDibujo;
anchoDelDibujo = 8.0;
altoDelDibujo = 4.5;
superficieDelDibujo = anchoDelDibujo * altoDelDibujo;
}
calculaAreaDelCirculo() // [3.9]
{
}

Ha sido fácil, pero nuestra función definida desde la línea [3.9] aún no hace nada. Observa que la especificación de la función
está fuera del cuerpo de la función main() . En otras palabras, las funciones no están anidadas.

Queremos que nuestra nueva función calculaAreaDelCirculo() sea llamada desde la función main() . Veamos cómo
podemos hacerlo [4].

//[4]
main()
{
float anchoDelDibujo, altoDelDibujo, superficieDelDibujo,
radioDelCirculo, superficieDelCirculo; // [4.4]
anchoDelDibujo = 8.0;
altoDelDibujo = 4.5;
radioDelCirculo = 5.0; // [4.7]
superficieDelDibujo = anchoDelDibujo * altoDelDibujo;
// ¡Aquí es donde llamamos a nuestra función!
superficieDelCirculo = calculaAreaDelCirculo(radioDelCirculo); // [4.10]
}

Nota: no mostramos el resto del programa (ver [3]).

Pasar argumentos a la función


Hemos añadido un par de nombres de variable de tipo float [4.4], y hemos inicializado la variable radioDelCirculo
dándole un valor [4.7].
Tiene más interés la línea [4.10], en la que llamamos a la función calculaAreaDelCirculo() . Como puedes ver, el nombre
de la variable radioDelCirculo se ha puesto entre paréntesis. Es un argumento de la función calculaAreaDelCirculo() .
El valor de la variable radioDelCirculo se pasa a la función calculaAreaDelCirculo() . Cuando la función
calculaAreaDelCirculo() ha hecho su tarea debe devolver un valor, en este caso el resultado del cálculo de la superficie.
Modifiquemos el código de la función calculaAreaDelCirculo() [5].

Nota: sólo se muestra el código de la función calculaAreaDelCirculo() .

//[5]
calculaAreaDelCirculo(float radio) // [5.1]
{
float area;
area = 3.1416 * radio * radio; // pi veces el cuadrado del radio [5.4]
return area;
}

En [5.1] definimos que se requiere un valor de tipo float como entrada para la función calculaAreaDelCirculo() . Cuando
se recibe, ese valor es almacenado en una variable llamada radio . Usamos una segunda variable, area , para almacenar el
resultado del cálculo en [5.4], así que la declaramos en [5.3] de la misma forma que hemos declarado variables en la función
main() [4.4]. Verás que la declaración de la variable radio se ha hecho dentro de los paréntesis [5.1]. La línea [5.5] devuelve
el resultado a la parte del programa desde la que fue llamada esta función. Como consecuencia, en la línea [4.10], se asigna ese
valor a la variable superficieDelCirculo .

La función en el ejemplo [5] está completa, excepto por una cosa. No hemos especificado el tipo de datos que devolverá la
función. El compilador nos va a requerir ese dato, así que no nos queda otra opción que obedecerle e indicar que es de tipo
float [6.1].

//[6]
float calculaAreaDelCirculo(float radio) //[6.1]
{
float area;
area = 3.1416 * radio * radio;
return area;

http://www.cocoalab.com/?q=book/export/html/60 Página 10 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Como indica la primera palabra de la línea [6.1], el dato devuelto por esta función (en este caso el dato devuelto por la variable
area ), es de tipo float . Como programador, debes asegurarte de que la variable superficieDelCirculo en la función
main() es también de ese tipo, para que el compilador no nos moleste sobre ese asunto.

No todas las funciones requieren argumentos. Si no hay ninguno, los paréntesis siguen siendo obligatorios, aunque no tengan
contenido.

//[7]
int tiraElDado()
{
int numeroDePuntos;
// Aquí se escribiría código para generar un número aleatorio entre 1 y 6
return numeroDePuntos;
}

Devolución de valores
No todas las funciones devuelven un valor. Si una función no devuelve un valor, entonces es de tipo void (que significa
"vacío"). En este caso, la sentencia return es opcional. Si la usas, entonces la palabra return debe ir sola, sin indicarle a
continuación un valor o nombre de variable.

//[8]
void alarmaXVeces(int x);
{
// Código para hacer que suene la alarma x veces
return;
}

Si la función tiene más de un argumento, como en la función calculaAreaDelDibujo() que está a continuación, los
argumentos van separados por comas ( , ).

//[9]
float calculaAreaDelDibujo(float ancho, float alto)
{
// Código para calcular la superficie...
}

Por convenio, la función main() debería devolver un entero y, por tanto, debería tener también una sentencia return . Debería
devolver 0 (cero, [10.9]) para indicar que todo se ha ejecutado sin problemas. Ya que devuelve un entero, debemos escribir int
antes de main() [10.1]. Pongamos junto todo el código que tenemos.

//[10]
int main() // [10.1]
{
float anchoDelDibujo, altoDelDibujo, areaDelDibujo,
radioDelCirculo, superficieDelCirculo;
anchoDelDibujo = 8;
altoDelDibujo = 4.5;
radioDelCirculo = 5.0;
areaDelDibujo = anchoDelDibujo * altoDelDibujo;
superficieDelCirculo = calculaAreaDelCirculo(radioDelCirculo); // [10.8]
return 0; // [10.9]
}
float calculaAreaDelCirculo(float radio) // [10.12]
{
float area; // [10.14]
area = 3.1416 * radio * radio;
return area;
}

Hacer que todo funcione


Como puedes ver en [10], tenemos una función main() y otra función que hemos definido nosotros mismos [10.12]. Si
intentásemos compilar este código, el compilador lo rechazaría. En la línea [10.8] indicaría que no conoce ninguna función
llamada calculaAreaDelCirculo() . ¿Por qué? Aparentemente el compilador comienza leyendo la función main() y de
repente encuentra algo que desconoce. No va más allá y nos muestra este aviso. Para satisfacer al compilador, simplemente
debemos añadir una declaración de función antes de la línea con el main() [11.1]. No tiene complicación, ya que es la misma

http://www.cocoalab.com/?q=book/export/html/60 Página 11 de 59
BecomeAnXcoder-Español 19/05/10 20:25

línea que en [10.12] excepto que termina con punto y coma ( ; ). Ahora el compilador no se llevará una sorpresa cuando se
encuentre la llamada a esa función.

//[11]
float calculaAreaDelCirculo(float radio); // [11.1] declaración de la función
int main()
{
// Aquí va el código de la función main...
}

Nota: no se muestra aquí el resto del programa (ver [10]).

En seguida compilaremos el programa en la realidad. Pero antes un par de comentarios.

Cuando escribas programas es importante que intentes tener en mente la posibilidad de reutilizar tu código en un futuro. Nuestro
programa podría tener una función calculaAreaDelRectangulo() tal como la que se muestra a continuación [12], que
podría llamarse desde la función main() . Esto sería útil incluso aunque sólo se llamase a esa función una vez. La función
main() sería más fácil de leer. Si tuviéramos que depurar el código sería más fácil encontrar el error analizando cada función
que siguiendo una larga secuencia de instrucciones.
//[12]
float calculaAreaDelRectangulo(float largo, float ancho) // [12.1]
{
return (largo * ancho); //[12.3]
}

Como puedes ver, en un caso simple como este, es posible agrupar en una sola instrucción el cálculo y la devolución del
resultado [12.3]. En [10.14] usé la variable area simplemente para mostrar cómo declarar una variable dentro de una función.

Aunque las funciones que definimos en este capítulo son bastante sencillas, es importante darse cuenta de que se puede
modificar el contenido de una función sin que ello afecte al código que la llama. Lo que no debe cambiarse es la declaración de
la función (es decir, su primera línea).

Por ejemplo, podemos cambiar el nombre de las variables internas de la función y seguirá trabajando (y esto no influirá en el
resto del programa). Alguien podría escribir la función y tú podrías utilizarla sin conocer su interior. Todo lo que necesitas es
saber cómo usarla. Ello implica conocer:

el nombre de la función
el número, orden y tipo de cada argumento
Lo que devuelve la función y el tipo del resultado

En el ejemplo [12], esas respuestas son, respectivamente:

calculaAreaDelRectangulo
Dos argumentos, ambos de tipo float , siendo el primero el alto y el segundo el ancho.
La función devuelve la superficie, y el resultado es de tipo float (como podemos deducir de la primera palabra de la
línea [12.1]).

Variables protegidas
El código de cada función está protegido del programa principal y de cualquier otra función.

Esto significa que el valor de una variable interna de una función por defecto no puede ser modificado por ninguna otra variable
de ninguna otra función, incluso aunque tuvieran el mismo nombre. Esta es una característica esencial de Objective-C. En el
capítulo 5 volveremos a discutir este comportamiento. Pero antes vamos a arrancar Xcode y ejecutar el programa anterior [10].

04: Salida en pantalla


Introducción
Hemos hecho grandes progresos con nuestro programa, pero aún no hemos visto como mostrar los resultados de nuestros
cálculos. El lenguaje Objective-C por si mismo no sabe como hacerlo, pero por suerte podemos utilizar funciones que han
escrito otros ya. Hay varias opciones para mostrar resultados por pantalla. En este libro usaremos una función incluida en el
entorno Cocoa de Apple: la función NSLog() . Esto es estupendo, porque no tenemos que preocuparnos (ni tenemos que

http://www.cocoalab.com/?q=book/export/html/60 Página 12 de 59
BecomeAnXcoder-Español 19/05/10 20:25

programar nada al respecto) para obtener nuestros resultados en la pantalla.

Así que ¿dónde muestra los datos NSLog() ? En Xcode existe la Consola para visualizar los mensajes de log. Para abrir la
Consola, debemos seleccionar [Console] desde el menú [Run] (Cmd-Shift-R). Una vez que construyamos y ejecutemos nuestra
aplicación, todos los mensajes aparecerán por ahí.

La función NSLog() se diseñó para mostrar mensajes de error, no para los resultados de una aplicación. De todas formas es tan
fácil de usar que la hemos adoptado en este libro para visualizar nuestros resultados. Una vez que conozcas Cocoa en
profundidad descubrirás técnicas más sofisticadas para hacerlo.

Uso de NSLog
Veamos como usar la función NSLog() con el siguiente código:
//[1]
int main()
{
NSLog(@"Julia es mi actriz favorita.");
return 0;
}

Al ejecutarlo, se producirá la aparición del texto "Julia es mi actriz favorita" en la Consola. El texto entre @" y " (lo que está
entre las comillas dobles) es lo que se llama "cadena de caracteres", "cadena de texto" o simplemente "cadena" (en inglés
"string").

Además de ese texto, la función NSLog() muestra información adicional, como la fecha actual y el nombre de la aplicación.
Por ejemplo, la salida completa del programa [1] en mi sistema es:

2010-03-12 22:12:38.052 prueba1[5006:a0f] Julia es mi actriz favorita.

Una cadena puede tener una longitud de cero o más caracteres.

Nota: en los siguientes ejemplos sólo se muestran las sentencias interesantes de la función main()

//[2]
NSLog(@""); //[2.1]
NSLog(@" "); //[2.2]

La sentencia [2.1] contiene 0 caracteres y la llamamos cadena vacía (tiene una longitud 0). La sentencia [2.2] no es una cadena
vacía aunque lo parezca. Contiene un espacio entre las comillas así que su longitud es 1.

Hay algunas secuencias de caracteres que tienen un significado especial dentro de las cadenas. Se les llama "secuencias de
escape".

Por ejemplo para hacer que la última palabra de nuestra cadena empiece en una línea nueva, debemos incluir un código especial
en la sentencia [3.1]. El código es \n , que significa "carácter de nueva línea".

//[3]
NSLog(@"Julia es mi actriz \nfavorita.");

Ahora la salida tiene un aspecto como este (sólo se muestra el contenido relevante):
Julia es mi actriz
favorita.

La contrabarra ( \ ) en [3.1] se llama carácter de escape, ya que indica a la función NSLog que el siguiente carácter no debe ser
impreso directamente en pantalla sino que tiene un significado especial: en este caso la "n" significa "salta a la siguiente línea".

En el caso (no muy habitual) de que quisieras mostrar un contrabarra en pantalla, podría parecer que tienes un problema. Si el
carácter tras la contrabarra tiene un significado especial, ¿cómo será posible imprimir una contrabarra?. Pues simplemente
poniendo dos contrabarras juntas. Esto indicará a la función NSLog que debe imprimir la segunda contrabarra. Aquí tenemos un
ejemplo:

//[4]
NSLog(@"Julia es mi actriz favorita.\\n");

http://www.cocoalab.com/?q=book/export/html/60 Página 13 de 59
BecomeAnXcoder-Español 19/05/10 20:25

La sentencia [4.1] producirá, tras la ejecución, la siguiente salida:


Julia es mi actriz favorita.\n

Mostrar variables
Hasta ahora sólo hemos mostrado cadenas estáticas. Imprimamos ahora el resultado de un cálculo.

//[5]
int x, numeroAMostrar;
x = 1;
numeroAMostrar = 5 + x;
NSLog(@"El valor del entero es %d.", numeroAMostrar);

Fíjate que, entre los paréntesis, tenemos una cadena, una coma y el nombre de una variable. La cadena contiene algo curioso:
%d . Al igual que la contrabarra, el carácter de porcentaje ( % ) tiene un sentido especial. Si va seguido de una d (abreviatura para
indicar número entero en sistema decimal), hace que en esa posición se inserte el valor que va a continuación de la coma, en
este caso el contenido de la variable numeroAMostrar . Al ejecutar el ejemplo [5] el resultado será:

El valor del entero es 6.

Para mostrar un número con decimales (en inglés se llama tipo "float"), usaremos %f en lugar de %d .

//[6]
float x, numeroAMostrar;
x = 12345.09876;
numeroAMostrar = x/3.1416;
NSLog(@"El valor del número con decimales es %f.", numeroAMostrar);

Más tarde, cuando aprendas a hacer repeticiones de cálculos, podrías queres realizar una tabla de valores. Imagina una tabla de
conversión de grados Fahrenheit a Celsius. Si quieres que los datos mostrados tengan buena apariencia, necesitarás que los
datos en cada una de las dos columnas tengan un ancho fijo. Puedes especificar ese ancho introduciendo un número entero entre
% y f (o entre % y d según el tipo de variable). Aún así, si el ancho que especificas es menor que el ancho del número,
prevalecerá el ancho del número.

//[8]
int x = 123456;
NSLog(@"%2d", x);
NSLog(@"%4d", x);
NSLog(@"%6d", x);
NSLog(@"%8d", x);

La ejecución del ejemplo [8] producirá la siguiente salida:


123456
123456
123456
123456

En las dos primeras sentencias [8.2, 8.3] solicitamos demasiado poco espacio para que el número sea mostrado completamente,
pero se toma el espacio igualmente. Sólo en la sentencia [8.5] se especifica un ancho mayor que el del valor, y es donde
apreciamos los espacios adicionales que se han requerido para mostrar el número.

También es posible combinar la especificación del ancho y el número de decimales con los que queremos que se muestre el
dato.

//[9]
float x=1234.5678;
NSLog(@"Reserva espacio para 10, y muestra 2 dígitos significativos.");
NSLog(@"%10.2f", x);

Mostrar múltiples valores


Por supuesto es posible mostrar más de un valor o cualquier combinación de valores [10.3]. Lo que debes hacer es asegurarte de
indicar correctamente el tipo de cada dato ( int, float ), usando %d y %f .

//[10]
int x = 8;

http://www.cocoalab.com/?q=book/export/html/60 Página 14 de 59
BecomeAnXcoder-Español 19/05/10 20:25

float pi = 3.1416;
NSLog(@"El valor de x es %d, mientras que el valor de pi es %f.", x, pi);

Asignar los símbolos a los valores


Uno de los errores más comunes entre los principiantes es especificar incorrectamente el tipo en funciones como NSLog y otras.
Si tus resultados no son los esperados o el programa rompe sin una razón, revisa las sentencias en las que asignas los tipos de
dato.

Si es incorrecta la asignación del primer dato, puede que el segundo tampoco sea mostrado correctamente. Un ejemplo:

//[10b]
int x = 8;
float pi = 3.1416;
NSLog(@"El valor int es %f, mientras que el valor float es %f.", x, pi);
// Lo correcto sería : NSLog(@"El valor int es %d, mientras que el valor float es %f.", x, pi);

produce la siguiente salida por consola:

El valor int es 3.141600, y el float es nan.

Vincular con la librería Foundation


Estamos a solamente una pregunta y una respuesta de ejecutar nuestro primer programa.

¿Cómo hace nuestro programa para conocer la función NSLog() ? Bien, realmente no la conoce, a menos que nosotros se lo
digamos. Para hacerlo, tenemos que indicar al compilador que importe la librería en la que está implementada la función
NSLog() (junto a otras muchas que iremos conociendo). La sentencia es la siguiente:

#import <Foundation/Foundation.h>

Ésta debe ser la primera sentencia en nuestro programa. Si juntamos todo lo que hemos aprendido en este capítulo obtendremos
el siguiente código, que haremos funcionar en el siguiente capítulo.

//[11]
#import <Foundation/Foundation.h>
float calculaAreaDelCirculo(float radio);
float calculaAreaDelRectangulo(float ancho, float alto);
int main()
{
float anchoDelDibujo, altoDelDibujo, areaDelDibujo,
radioDelCirculo, areaDelCirculo;
anchoDelDibujo = 8.0;
altoDelDibujo = 4.5;
radioDelCirculo = 5.0;
areaDelDibujo = calculaAreaDelRectangulo(anchoDelDibujo, altoDelDibujo);
areaDelCirculo = calculaAreaDelCirculo(radioDelCirculo);
NSLog(@"Area del círculo: %10.2f.", areaDelCirculo);
NSLog(@"Area del cuadrado: %f.", areaDelDibujo);
return 0;
}

float calculaAreaDelCirculo(float radio) // primera función personalizada


{
float area;
area = 3.1416 * radio * radio;
return area;
}
float calculaAreaDelRectangulo(float ancho, float alto) // segunda función personalizada
{
return ancho* alto;
}

05: Compilación y ejecución de un Programa


Introducción

http://www.cocoalab.com/?q=book/export/html/60 Página 15 de 59
BecomeAnXcoder-Español 19/05/10 20:25

El código que hemos escrito hasta ahora no es más que texto relativamente sencillo de leer para nosotros. No es que sea prosa
precisamente, pero es aún peor para nuestro Mac. ¡No puede hacer nada con él! Se necesita un programa especial, llamado
compilador, para convertir este texto en un conjunto de instrucciones que el Mac pueda entender y ejecutar. El compilador es
parte de Xcode, el entorno de programación gratuito de Apple. Deberías haber instalado Xcode desde el disco que viene con la
copia de Mac OS X. En cualquier caso, verifica que tienes la última versión, que puedes descargar en
http://developer.apple.com (se requiere registro gratuito).

Crear un proyecto
Arranca Xcode, que encontrarás en /Developer/Applications. La primera vez te hará responder algunas preguntas. Acepta las
sugerencias que él haga, en principio son adecuadas y además podrás modificarlas más adelante en el menú Preferencias. Para
empezar realmente, selecciona New Project en el menú File. Aparece una ventana de diálogo con los tipos de proyecto
disponibles. El aspecto puede variar ligeramente según la versión de Xcode.

El asistente de Xcode te permite crear nuevos proyectos.

En este momento queremos crear un programa simple en Objective-C, sin GUI (Interfaz gráfica de usuario), así que dentro de
Command Line Tool selecciona Type Foundation.

http://www.cocoalab.com/?q=book/export/html/60 Página 16 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Introduce un nombre para tu aplicación, como "justatry". Selecciona el lugar en el que quieres guardar tu proyecto y pulsa
Finish.

El proyecto que estamos creando va a poder ejecutarse desde el Terminal (/Aplicaciones/Utilidades/Terminal). Si quieres
evitarte molestias, asegúrate de que el nombre del proyecto consta de una sola palabra (sin espacios). También es costumbre que
los nombres de programas que se ejecutan en terminal comiencen por minúscula. Por el contrario, los nombres de programas
con interfaz gráfica suelen comenzar por mayúscula.

Explorando Xcode
A continuación se muestra una ventana que tú como programador verás con frecuencia. Tiene dos marcos principales a derecha
e izquierda. El de la izquierda es "Groups & Files", desde el que accedemos a todos los elementos de los que consta nuestro
proyecto. En este momento no hay demasiados, pero cuando creemos programas con interfaz gráfica (GUI) y multiidioma, aquí
veremos todos los ficheros relacionados con la GUI y con los diferentes idiomas. Los ficheros se agrupan en carpetas, pero no
busques esas carpetas en tu Mac con el Finder ya que son virtuales; aparecen aquí para organizar nuestro trabajo.

En el marco "Groups & Files" abre el grupo justatry (pulsando el triángulo gris que está a la izquierda de su nombre) y dentro
de éste abre el grupo Source. Dentro encontrarás un fichero llamado justatry.m [1]. ¿Recuerdas que todo programa debe
contener una función llamada main() ? Bien, este es el fichero que contiene la función main() . Más tarde en este capítulo
vamos a modificarla para incluir el código de nuestro programa. Si abres justatry.m te llevarás una sorpresa: Apple ha creado
ya por ti la función main() .

http://www.cocoalab.com/?q=book/export/html/60 Página 17 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Xcode mostrando la función main().


//[1]
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) //[1.2]
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; //[1.4]
// insert code here...
NSLog(@"Hello, World!");
[pool drain]; //[1.7]
return 0;
}

Echa un vistazo al código y busca elementos que puedas reconocer. Verás:

La sentencia import necesaria para poder utilizar funciones como NSLog() .


La función main() .
Las llaves entre las que debemos encerrar el código de nuestro programa.
Un comentario, que nos invita a escribir código en esa posición.
Una instrucción con NSLog() , para mostrar una cadena de texto en pantalla.
Una sentencia return 0; .

Pero también hay algunas cosas que no reconocemos:

Los argumentos que se le pasan a la función main() . [1.2]


Una línea que empieza por NSAutoreleasePool [1.4]
Otra línea que contiene las palabras pool y drain [1.7].

Personalmente no me gusta que los autores de libros me muestren a mi, como lector, código lleno de elementos desconocidos y
me prometan que más adelante lo veré todo claro. Por eso he preferido explicar en capítulos anteriores lo que son las funciones,
para que no te enfrentes ahora a demasiados conceptos nuevos.

Así que ahora ya sabes que las funciones son una forma de organizar el código, que todos los programas tienen una función
main() y cual es el aspecto de las funciones. Aún así, debo admitir que por ahora no puedo explicar completamente todo lo que
ves en el ejemplo [1]. Siento tener que pedirte que ignores lo que ves en [1.2, 1.4 y 1.7]. Antes debes familiarizarte con otros
elementos de Objective-C. La buena noticia es que ya has pasado dos capítulos complicados y los tres siguientes son bastante
llevaderos, antes de que tengamos que tratar de nuevo con cuestiones complejas.

http://www.cocoalab.com/?q=book/export/html/60 Página 18 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Si realmente no aguantas sin una explicación, aquí va un resumen.

Los argumentos que se pasan a la función main() son necesarios para poder ejecutar el programa en el Terminal.

Los programas necesitan memoria para funcionar y deben dejarla a disposición del resto cuando ya no es necesaria. Al
comienzo del programa, en [1.4], solicitamos la memoria y en [1.7] la liberamos justo antes de que el programa termine.

Build and run (Compilar y ejecutar)


Ejecutemos el programa que ha preparado Apple [1]. En primer lugar necesitamos abrir la ventana Console (Consola), que está
en el menú Run, para ver los resultados. Después pulsaremos el icono del martillo con el texto "Build and Run" para que se
compile y ejecute el programa.

El botón Build and Run.

El programa se ejecuta y se muestran sus resultados en la ventana Console, junto con información adicional. La última línea
notifica que el programa ha finalizado con un valor de estado 0 . Ese es el valor que ha devuelto la función main() , tal como
vimos en el capítulo 3 [7.9]. Por tanto, nuestro programa ha llegado hasta la última línea sin haber terminado prematuramente.
¡No está mal para empezar!

Control de errores
Vayamos al ejemplo [1] y veamos qué sucede cuando hay un error en el programa. Por ejemplo, he reemplazado la sentencia
NSLog() con otra, pero he olvidado poner el carácter punto y coma al final.

//[2]
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
NSLog(@"Julia es mi actriz favorita") //¡Oh, he olvidado el punto y coma!
[pool drain]; //[2.9]
return 0;
}

Para compilar la aplicación pulsa el icono Build en la barra de herramientas (si no lo tienes, pulsa la opción Build dentro del
menú Build). Aparecerá un indicador rojo antes de la línea [2.9].

Xcode señala un error de compilación.

Según la versión de Xcode podrás ver una descripción del error a la derecha de la línea o tendrás que pulsar en el marcador rojo
para que se despliegue la descripción del error.

Lo primero que hace el compilador es analizar el código, recorriendo cada línea para comprobar si puede entender su contenido.
Nosotros, para ayudarle, tenemos que dejarle algunas pistas. Por ejemplo, antes de cada sentencia import hay que poner una
almohadilla ( # ). También, para indicar el final de una instrucción, hay que poner un punto y coma. En el momento en que llega
a la línea [2.9] es cuando el compilador se da cuenta de que algo va mal, pero no sabe que el problema no está en esta línea sino

http://www.cocoalab.com/?q=book/export/html/60 Página 19 de 59
BecomeAnXcoder-Español 19/05/10 20:25

en la anterior, en la que falta el punto y coma. La lección que debemos aprender es que la información que nos da el compilador
no siempre es una descripción precisa del error, e incluso puede que no sea exacta la posición del error (aunque seguro que está
muy cerca).

Arregla el programa añadiendo el punto y coma y ejecútalo de nuevo para asegurarte de que funciona.

Nuestra primera aplicación


Ahora vamos a coger el programa que preparamos en el capítulo anterior y lo mezclamos con el código que ha escrito ya Apple.
Debería quedar algo así [3]:

//[3]
#import <Foundation/Foundation.h>
float calculaAreaDelCirculo(float radio); //[3.3]
float calculaAreaDelRectangulo(float ancho, float alto); //[3.4]
int main(int argc, const char * argv[]) // [3.6]
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
float anchoDelDibujo, altoDelDibujo, areaDelDibujo,
radioDelCirculo, areaDelCirculo;
anchoDelDibujo = 8.0;
altoDelDibujo = 4.5;
radioDelCirculo = 5.0;
areaDelDibujo = calculaAreaDelRectangulo(anchoDelDibujo, altoDelDibujo);
areaDelCirculo = calculaAreaDelCirculo(radioDelCirculo);
NSLog(@"Area del círculo: %10.2f.", areaDelCirculo);
NSLog(@"Area del cuadrado: %f.", areaDelDibujo);
[pool drain];
return 0;
}
float calculaAreaDelCirculo(float radio) // [3.22]
{
float area;
area = 3.1416 * radio * radio;
return area;
}
float calculaAreaDelRectangulo(float ancho, float alto) // [3.29]
{
return ancho * alto;
}

Toma tu tiempo para asegurarte de que entiendes la estructura del programa. Tenemos las declaraciones de nuestras propias
funciones en [3.3 y 3.4] antes de la función main() en la línea [3.6]. Nuestras funciones están implementadas fuera de las
llaves de la función main() y hemos puesto el cuerpo de nuestra función main() en el lugar que nos había indicado Apple.

Cuando ejecutemos el programa, obtendremos la siguiente salida:

Running…
2010-03-14 00:54:24.494 justatry[8613:a0f] Area del círculo: 78.54.
2010-03-14 00:54:24.496 justatry[8613:a0f] Area del cuadrado: 36.000000.
Debugger stopped.
Program exited with status value:0.

Depurando
Según se van complicando los programas, se hacen más difíciles de depurar. Xcode nos da la opción de saber qué sucede dentro
del programa mientras está corriendo. Para ello haremos click con el ratón en el margen gris que está a la izquierda del código
(en la zona en la que aparecen los números de línea), en la línea en la que queremos que el programa nos muestre los valores de
las variables. En ese punto Xcode insertará un "breakpoint" (punto de ruptura), representado por una flecha azul.

http://www.cocoalab.com/?q=book/export/html/60 Página 20 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Colocando breakpoints (puntos de ruptura) en nuestro código. En este caso podemos ver uno en la línea 15

En la siguiente sección veremos cómo el Debugger nos muestra el estado de las variables al llegar al punto de ruptura. Pero ten
en cuenta que serán los valores de "antes" de que se ejecute la línea en la que hemos parado, así que puede que te convenga
poner el breakpoint "después" de la línea que te interesa.

En cuanto insertes el primer breakpoint verás que el icono con el martillo cambia ligeramente y en el texto se lee "Build and
Debug" (Compilar y depurar). En versiones anteriores tienes que mantener pulsado el ratón en el icono del martillo hasta que
aparezca un menú.

El botón de compilar y depurar.

Para seguir lo que está sucediendo necesitas abrir dos ventanas: Console y Debugger, que están en el menú Run. La Consola
mostrará un texto parecido a este:

[Session started at 2009-06-03 15:48:02 +1000.]


Loading program into debugger…
GNU gdb 6.3.50-20050815 (Apple version gdb-956) (Wed Apr 30 05:08:47 UTC 2008)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin".tty /dev/ttys000
Program loaded.
sharedlibrary apply-load-rules all
run
[Switching to process 86746 local thread 0x2d03]
Running…

Esto quiere indica que nuestra aplicación ha sido compilada y lanzada, y que se ha cargado el Debugger (depurador).

La ventana del Debugger tendrá un aspecto parecido a este:

http://www.cocoalab.com/?q=book/export/html/60 Página 21 de 59
BecomeAnXcoder-Español 19/05/10 20:25

El Depurador de Xcode te permite ejecutar el programa paso a paso y consultar el valor de las variables.

El programa se ejecutará hasta que alcance el primer breakpoint. Si compruebas el panel superior derecho puedes leer el valor de
las variables. Se muestran en color rojo los valores que han cambiado desde el anterior breakpoint. Para continuar la ejecución
pulsa el botón Continue. Los botones Step Over y Step Into sirven para ejecutar el programa instrucción a instrucción. Prueba el
Debugger durante un rato para familiarizarte con él, es una herramienta poderosa.

Conclusión
Ya tenemos todo lo necesario para escribir, depurar y ejecutar programas sencillos para Mac OS X.

Si no deseas realizar programas con interfaz gráfico, todo lo que te falta es ir conociendo en profundidad Objective-C para
desarrollar programas no gráficos más sofisticados. En los siguientes capítulos vamos a hacer exactamente eso. Y después, nos
sumergiremos en aplicaciones con GUI (Interfaz Gráfico de Usuario). ¡Sigue leyendo!

06: Sentencias condicionales


if()
A veces vas a querer que tu código realice una serie de acciones sólo si se dan unas determinadas condiciones. Veamos un
ejemplo sencillo [1.2].

//[1]
// 'edad' es una variable de tipo int en la que guardamos la edad del usuario
if (edad > 30) // [1.2] El símbolo > significa "mayor que"
{

http://www.cocoalab.com/?q=book/export/html/60 Página 22 de 59
BecomeAnXcoder-Español 19/05/10 20:25

NSLog(@"La edad es mayor que 30."); //[1.4]


}
NSLog(@"Terminado."); //[1.6]

La línea [1.2] contiene una instrucción if() , también conocida como instrucción condicional. Verás que a continuación tiene
unas llaves que encierran el código que queremos que se ejecute cuando sea verdadera la condición que se indica entre
paréntesis. En este caso, si la condición edad > 30 es cierta, entonces se mostrará la cadena que vemos en [1.4]. En cualquier
caso, sea cierta o no esa condición, siempre se va a mostrar la cadena en [1.6], ya que está fuera de las llaves de la instrucción
if() .

if() else
También podemos indicar una serie de instrucciones que queremos que se realicen cuando no sea cierta la condición, usando la
sentencia if…else [2].

//[2]
// 'edad' es una variable entera en la que guardamos la edad del usuario
if (edad > 30) //[2.2]
{
NSLog(@"La edad es mayor que 30."); //[2.4]
}
else
{
NSLog(@"La edad es inferior a 30."); //[2.7]
}
NSLog(@"Terminado.");

La cadena de la sentencia [2.7] sólo se mostrará cuando no sea cierta la condición edad > 30 .

Comparaciones
Además del "mayor que" que hemos visto en [2.2], tenemos a nuestra disposición otros operadores para comparar números.

== igual a
> mayor que
< menor que
>= mayor o igual que
<= menor o igual que
!= distinto de

Presta especial atención a que el operador para comparar la igualdad tiene dos signos de igual y es muy fácil olvidarse esto y
utilizar un solo signo de igualdad. Como ya hemos visto, un solo signo igual lo que hace es asignar un valor a una variable en
lugar de compararla con ese valor. Este es un error muy frecuente, así que repite conmigo en alto: ¡No voy a olvidar escribir dos
signos de igualdad cuando vaya a comparar la igualdad!

Los operadores de comparación son bastante útiles cuando quieres repetir una serie de instrucciones varias veces. Esto será un
tema para el siguiente capítulo. Antes discutiremos otros aspectos de las sentencias condicionales.

Ejercicio
Echemos un vistazo de cerca al hecho de la comparación. Una operación de comparación puede tener solamente dos resultados:
que sea verdadera o que sea falsa.

En Objective-C, verdadero y falso se representan, respectivamente, por 1 y 0 . Incluso hay un tipo de dato especial, llamado
BOOL , que puedes utilizar para representar esos valores. Para indicar el valor "verdadero", puedes emplear tanto 1 como YES .
Para indicar un valor "falso", puedes emplear tanto 0 como NO .

//[3]
int x = 3;
BOOL y;
y = (x == 4); // después de esta instrucción, la variable 'y' tendrá el valor 0.

Es posible comprobar más de una condición. Cuando deban ser ciertas todas las condiciones, usaremos el operador representado
por dos ampersands: && . Si basta con que sea cierta una de las condiciones, usaremos el operador representado por dos barras
verticales: || .

//[4]

http://www.cocoalab.com/?q=book/export/html/60 Página 23 de 59
BecomeAnXcoder-Español 19/05/10 20:25

// Condiciones con el operador lógico Y


if ( (edad > 18) && (edad < 65) ) // Si es mayor de 18 y es menor de 65
{
NSLog(@"Probablemente necesite trabajar para vivir.");
}
//
// Condiciones con el operador lógico O
if ( (kilometrosRecorridos > 100000) || (antiguedad > 4) ) {
// Si ha recorrido más de 100000 km o tiene más de 4 años
NSLog(@"Debe revisar el coche.");
}

También es posible anidar sentencias condicionales. Es tan sencillo como poner una sentencia condicional dentro de las llaves
de otra sentencia condicional. Primero se evalúa la condición exterior y, sólo si es cierta, se evaluará la condición en su interior:

//[5]
if (edad >= 18) // Si es mayor o igual que 18
{
if (edad < 65) // Si es menor que 65
{
NSLog(@"Probablemente necesite trabajar para vivir.");
}
}

07: Ejecución de bucles


Introducción
En todo el código que hemos visto hasta ahora, cada instrucción se ejecutaba solamente una vez. Siempre podríamos volver a
ejecutar funciones llamándolas repetidamente [1].

//[1]
NSLog(@"Julia es mi actriz favorita.");
NSLog(@"Julia es mi actriz favorita.");
NSLog(@"Julia es mi actriz favorita.");

Pero eso requiere repetir la llamada cada vez. Como todos los lenguajes de programación, Objective-C ofrece varias formas de
ejecutar un bucle de instrucciones.

for()
Si sabes el número de veces que quieres repetir la instrucción (o secuencia de instrucciones), puedes especificarlo en una
sentencia for() tal como la que vemos en el ejemplo [2]. El número de repeticiones debe ser un número entero, ya que no se
puede repetir una operación, por ejemplo, 2,7 veces.
//[2]
int x;
for (x = 1; x <= 10; x++) //[2.2]
{
NSLog(@"Julia es mi actriz favorita."); //[2.4]
}
NSLog(@"El valor de x es %d", x); //[2.6]

En el ejemplo [2], la cadena en [2.4] se va a imprimir 10 veces. En una sentencia for() vamos a encontrar entre los paréntesis
tres secciones separadas por punto y coma ( ; ). La secuencia es la siguiente:

[1] Se ejecuta la sección 1 del for


[2] Se evalúa la sección 2 del for
Si es cierta, entonces,
se ejecutan las instrucciones que hay dentro de las llaves
se ejecuta la sección 3 del for
se salta al paso [2]
Si no es cierta:
se sale del bucle for

http://www.cocoalab.com/?q=book/export/html/60 Página 24 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Vamos a explicar la secuencia con el ejemplo [2]. Primero se asigna a x el valor 1 . Después se evalúa la condición, que en este
caso es x <= 10 . La condición se cumple, ya que la primera vez x es igual a 1 , por lo tanto se ejecutarán los comandos en el
interior de las llaves del for() . Como la condición ha sido cierta, se ejecuta la sección 3, que en este caso incrementa el valor
de x en 1 (eso es lo que significa x++ ). Así que ahora x es igual a 2 y se vuelve a evaluar la expresión x <= 10 . Como sigue
siendo cierta, se vuelven a ejecutar las instrucciones entre llaves y se vuelve a incrementar en 1 el valor de x . Así seguirá
sucediendo hasta el momento en que x sea igual a 11 . En este momento la condición no se cumplirá y saldremos del bucle
for() . Hemos puesto la línea [2.6] para probar que cuando se llega ahí, x es igual a 11 .

Habrá ocasiones en que necesitemos otros incrementos distintos de x++ . En el ejemplo [3] vamos a convertir de grados
Fahrenheit a Celsius.

//[3]
float celsius, tempEnFahrenheit;
for (tempEnFahrenheit = 0; tempEnFahrenheit <= 200; tempEnFahrenheit = tempEnFahrenheit + 20)
{
celsius = (tempEnFahrenheit - 32.0) * 5.0 / 9.0;
NSLog(@"%10.2f -> %10.2f", tempEnFahrenheit, celsius);
}

La salida del programa será:

0.00 -> -17.78


20.00 -> -6.67
40.00 -> 4.44
60.00 -> 15.56
80.00 -> 26.67
100.00 -> 37.78
120.00 -> 48.89
140.00 -> 60.00
160.00 -> 71.11
180.00 -> 82.22
200.00 -> 93.33

while()
En Objective-C encontramos también otras formas de repetir una serie de instrucciones:

while () { }

y
do {} while ()

El funcionamiento es básicamente idéntico al bucle for() : empieza evaluando una condición y en el momento en que esa
condición sea falsa deja de ejecutar las instrucciones entre llaves.
//[4]
int contador = 1;
while (contador <= 10)
{
NSLog(@"Julia es mi actriz favorita.\n");
contador = contador + 1;
}
NSLog(@"El valor del contador es %d", contador);

El valor de contador al salir del bucle es 11 .

La instruction do {} while () es ligeramente diferente, ya que las instrucciones entre llaves se va a ejecutar siempre al
menos una vez. Eso es debido a que primero se ejecutan las instrucciones entre llaves y después de evalúa la condición entre
paréntesis.
//[5]
int contador = 1;
do
{
NSLog(@"Julia es mi actriz favorita.\n");
contador = contador + 1;
}
while (contador <= 10);
NSLog(@"El valor del contador es %d", contador);

http://www.cocoalab.com/?q=book/export/html/60 Página 25 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Podremos comprobar que el valor de contador al salir del bucle es 11 .

Hemos aumentado nuestro nivel como programadores y es el momento de abordar un objetivo más alto. En el siguiente capítulo
construiremos nuestro primer programa con Interfaz Gráfico de Usuario (GUI).

08: Programas con entorno gráfico

Introducción
Al haber incrementado nuestro conocimiento de Objective-C, estamos ya preparados para crear un programa con Interfaz
Gráfica de Usuario (GUI). En este punto debo confesar algo. Objective-C es una extensión de otro lenguaje de programación
llamado C. Hasta ahora, prácticamente todo lo que hemos visto es simplemente lenguaje C. Así que, ¿dónde está la diferencia
entre Objective-C y C?, pues precisamente en la parte "Objective". Objective-C trata con unos elementos abstractos llamados
objetos.

Hasta ahora hemos tratado principalmente con números, hemos visto como Objective-C crea números en memoria y podemos
manipularlos con operadores y funciones matemáticas. Esto nos viene bien cuando nuestra aplicación trabaja con números (por
ejemplo, una calculadora). Pero ¿qué ocurre si nuestra aplicación es, digamos, un reproductor de música que usará canciones,
listas de reproducción, artistas, etc.? ¿O si es un sistema de control de tráfico aéreo que tratará con aviones, vuelos, aeropuertos,
etc.? Sería bueno poder manipular tales elementos con la misma facilidad con la que podemos manipular números.

Y aquí acuden los objetos. Con Objective-C puedes definir las clases de objetos con los que quieres tratar y después escribir
aplicaciones para manipularlos.

Objetos en acción
Como ejemplo, veamos cómo se manejan las ventanas en un programa escrito en Objective-C, tal como Safari. Ve a una
ventana abierta de Safari en tu Mac; en la parte superior izquierda hay tres botones. El botón rojo es para cerrar. ¿Qué ocurre
cuando haces click en ese botón? Se envía un mensaje a esa ventana y en respuesta a dicho mensaje la ventana ejecuta código
para cerrarse.

Se envía un mensaje de cierre a la ventana

La ventana es un objeto. Puedes, por ejemplo, desplazarla. Los tres botones son objetos. Puedes pulsarlos. Estos objetos tienen
una representación visual en la pantalla, pero no es así con todos; por ejemplo el objeto que representa la conexión entre Safari y
un sitio web no tiene una representación visual.

Un objeto (por ej. la ventana) puede contener otros objetos (p.ej. los botones)

http://www.cocoalab.com/?q=book/export/html/60 Página 26 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Puedes tener tantas ventanas abiertas de Safari como quieras. Podrías pensar que los programadores de Apple:

a. Han programado previamente todas las posibles ventanas, usando su poder mental para anticiparse a todas las ventanas
que tú podrías querer abrir, o …
b. Hicieron una especie de plantilla y dejan que Safari cree cada ventana a partir de esa plantilla cuando haga falta.

Por supuesto, la respuesta correcta es la b. Crearon un código, llamado clase, que define la ventana, incluyendo su aspecto y
comportamiento. Cuando creas una ventana, realmente es la clase la que crea la ventana por ti. Esta clase representa el concepto
de ventana y cualquier ventana concreta es realmente una instancia de ese concepto (de la misma manera que 76 es una
instancia del concepto número).

Puedes imaginarte la clase como los planos de una casa, incluyendo la descripción de sus instalaciones, y objeto como cada una
de las casas reales que se han construido a partir de ese proyecto.

Variables de instancia
La ventana que has creado está colocada en una posición determinada de la pantalla. Si minimizas la ventana en el Dock y la
haces reaparecer, se coloca exactamente en donde estaba ¿Cómo lo hace? La clase define variables para recordar la posición y
cada instancia de esa clase, es decir, cada objeto, contiene sus valores de posición.

Métodos
La clase también nos da acceso a una serie de acciones que puede realizar. Una de las acciones de la clase "ventana" es cerrarse.
Cuando pulsas el botón para cerrar una ventana, el botón envía un mensaje de cierre a ese objeto de ventana. A esas acciones se
les llama métodos. Como verás, se parecen mucho al concepto de funciones que ya hemos visto, así que si nos has seguido hasta
aquí no vas a tener problema en aprenderlo.

Objetos en memoria
Cuando la clase crea un objeto de ventana para ti, reserva memoria (RAM) para almacenar su posición además de mucha otra
información. Sin embargo, no hace una copia del código para cerrar la ventana; eso sería un desperdicio de memoria ya que el
código es el mismo para todos los objetos de la misma clase. El código para cerrar la ventana necesita estar presente sólo una
vez, pero cada objeto de ventana ha de tener acceso a todo el código de la clase a la que pertenece.

Como ya vimos anteriormente, el código que vamos a ver en este capítulo contiene algunas líneas para reservar memoria y
dejarla a disposición del sistema al terminar. Pero aún es pronto para hablar sobre ello, lo veremos más adelante.

Ejercicio
Nuestra aplicación
Vamos a crear una aplicación con dos botones y un campo de texto. Si presionas un botón, aparecerá un valor en el campo de
texto. Si presionas el otro botón, se introducirá otro valor en el campo de texto. Piensa en ello como una calculadora de dos
botones que no puede hacer cálculos. Por supuesto, cuando aprendas más llegarás a hacer una calculadora real, pero es mejor ir
paso a paso.

Un esquema de la aplicación que queremos crear

Cuando se pulse uno de los botones de la aplicación, enviará un mensaje. El mensaje contiene el nombre del método que se va a
ejecutar. ¿A dónde se envía el mensaje? En el caso de la ventana, el mensaje de cierre se envía a ese objeto ventana, que es una
instancia de la clase ventana. Lo que necesitamos en nuestro caso es un objeto capaz de recibir mensajes de cada uno de los dos
botones y que pueda indicar al campo de texto que muestre un valor.

http://www.cocoalab.com/?q=book/export/html/60 Página 27 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Nuestra primera clase


Así que primero debemos implementar nuestra propia clase y luego crear una instancia de ella. Ese objeto será receptor de los
mensajes de los botones (ver esquema más abajo). Al igual que un objeto ventana nuestra instancia también es un objeto, pero no
a diferencia de las ventanas, nuestro objeto no tiene una representación visual; sólo es algo dentro de la memoria de nuestro
Mac.

Cuando nuestra instancia recibe un mensaje enviado por uno de los dos botones se ejecuta el método apropiado. Recordamos
que el código de ese método está almacenado en la clase, no en la propia instancia. Durante la ejecución, este método
modificará el texto del objeto campo de texto.

¿Cómo sabrá el método de nuestra clase cómo asignar el texto de un campo de texto? Realmente no lo sabe. Pero el propio
campo de texto sí sabe como modificar su propio texto. Así que enviaremos un mensaje al campo de texto pidiéndole que haga
el trabajo. ¿Qué contenido ha de tener ese mensaje? Por supuesto hay que indicar el objeto receptor del mensaje, que en este
caso es el campo de texto. También necesitamos indicar qué es lo que queremos que haga el receptor, es decir, en este caso hay
que dar el nombre del método que tiene el campo de texto para mostrar un texto (esto implica conocer los métodos que pone a
nuestra disposición un campo de texto, ya hablaremos sobre ello). En este caso, nuestro mensaje también debe contener el valor
que queremos que muestre. A los datos que hay que aportar al método (en este caso: el valor que queremos que muestre) se les
llama argumentos.

Un esquema del intercambio de mensajes entre objetos de nuestra aplicación

Este es el formato general para enviar mensajes en Objective-C, tanto sin argumentos [1.1], como con un argumento [1.2]:

//[1]
[receptor mensaje]; // [1.1]
[receptor mensajeQueRequiereUnArgumento:elArgumento]; // [1.2]

Como puedes ver en cada una de las sentencias, todo el contenido está encerrado entre corchetes, por supuesto con punto y
coma al final. Dentro de los corchetes, primero aparece el objeto receptor del mensaje, seguido del nombre del método que
vamos a invocar separado por espacio. Si se requiere un argumento, irá a continuación separado por dos puntos. [1.2].

Creación del proyecto


Veamos como llevar esto a la práctica. Arranca Xcode para crear un nuevo proyecto. Selecciona Cocoa Application. Dale un
nombre a tu proyecto, como "Mi primera apli" (por convención, el nombre de una aplicación con GUI debería comenzar por
mayúscula). En la parte izquierda, en la sección Groups & Files, abre la carpeta Resources y haz doble-click en MainMenu.xib.

http://www.cocoalab.com/?q=book/export/html/60 Página 28 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Haz doble-click en el fichero MainMenu.xib de Xcode

Si estás usando una versión anterior a Xcode 3, verás que el nombre del fichero será nib en lugar de xib. No tiene importancia
ya que los ficheros son iguales a todos los efectos.

Creación de la GUI (Interfaz gráfica de usuario)


Al abrir el fichero MainMenu.xib se abrirá otro programa, Interface Builder (traducido como Generador de Interfaces). Ya que
van a aparecer muchas ventanas, podría interesarte seleccionar la opción Hide Others (Ocultar el resto de ventanas) del menú
Interface Builder. Una de las ventanas tiene en el título el nombre que has dado a tu proyecto y no tiene contenido: es la que
verán los usuarios de tu aplicación. Si la ves demasiado grande puedes redimensionarla. Verás también otra ventana que se
llama "Library": es una especie de repositorio de todos los tipos de objetos que puedes tener en tu GUI. Selecciona el elemento
"Objects" en la parte superior de la ventana y desplázate por la lista hasta encontrar los botones (Push Button). Arrastra dos
botones a tu ventana de aplicación, uno cada vez. Sigue desplazándote más abajo en la lista de objetos hasta encontrar uno con
el texto "Label" y arrastra uno de estos objetos a tu ventana.

Podemos modificar el modo de presentación de los objetos en la ventana "Library" pulsando el pequeño botón con una rueda
dentada que hay en la parte inferior de la ventana: desde ver sólo los iconos, hasta que se incluya la descripción al lado de cada
objeto.

http://www.cocoalab.com/?q=book/export/html/60 Página 29 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Arrastrando objetos de la ventana "Library" hasta la ventana de tu aplicación.

Internamente, al arrastrar los objetos de la ventana "Library" a la ventana de aplicación, se crean esos objetos y se colocan en la
ventana.

Fíjate que al hacer click sobre los objetos de la ventana "Library", en la parte inferior aparece un nombre descriptivo, como
"Push Button" y debajo otro nombre como NSButton . Este último es el nombre de clase que proporciona Apple. Más tarde en
este capítulo veremos como encontrar los métodos que nos ofrecen estas clases, los cuales nos harán falta para realizar las
acciones necesarias en nuestro programa.

No olvides guardar el fichero regularmente (File -> Save) para que Interface Builder y Xcode se mantengan sincronizados.

Recoloca los objetos en tu ventana de aplicación para que queden con buen aspecto: arrástralos y redimensiónalos a tu gusto.
Puedes cambiar el texto de los botones haciendo doble-click sobre él. Es conveniente que explores la paleta de objetos y
practiques a añadir otros objetos a tu ventana.

Conociendo Interface Builder

Para cambiar las propiedades de un objeto, selecciónalo y pulsa Cmd-Shift-I. Por ejemplo selecciona tu ventana de aplicación,
pulsando en la barra de título superior de la ventana, y pulsa Cmd-Shift-I. Verás una ventana titulada "Window Attributes".
Puedes, por ejemplo, marcar la casilla "Textured" y tu ventana cambiará a un aspecto metálico. Experimenta seleccionando los
botones y el campo de texto: ¡puedes modificar un montón de propiedades de tu aplicación sin escribir una sola línea de código!

http://www.cocoalab.com/?q=book/export/html/60 Página 30 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Nuestra ventana en Interface Builder, junto al inspector de objetos

Trabajando con clases


Cierra Interface Builder y volvamos ahora a Xcode. En la ventana de proyecto, abre la carpeta Classes en el panel Groups &
Files. Verás dos ficheros, que son la clase básica que Xcode ha creado para nosotros. El fichero terminado en ".h" es la cabecera
(Header) con la interfaz de la clase; el que termina en ".m" es el fichero principal (Main) con la implementación del código de la
clase.

http://www.cocoalab.com/?q=book/export/html/60 Página 31 de 59
BecomeAnXcoder-Español 19/05/10 20:25

La clase Application Delegate que se incluye con cada aplicación Cocoa.

Cada aplicación Cocoa necesita al menos una clase para poder realizar algo útil. Por convenio a la clase básica se la conoce
como Delegada (Delegate), porque puede implementar una serie de métodos delegados para personalizar el comportamiento de
la clase NSApplication de Cocoa. Veremos esto más tarde.

Las clases a fondo


Veamos como funcionan las clases.

Para ahorrar esfuerzo de programación, sería bueno que pudiésemos construir encima de lo que otros ya han hecho, en lugar de
empezar a escribir desde cero. Si, por ejemplo, queremos crear una ventana con unas propiedades especiales, sólo deberíamos
necesitar añadir el código para esas propiedades y no tener que escribir el código para el resto del comportamiento de la
ventana, como minimizar o cerrar. Para construir encima de lo que otros programadores han hecho, heredaremos todo ese
comportamiento. Y eso es lo que hace a Objective-C tan diferente de C.

¿Cómo se hace? Bien, tenemos una clase ventana ( NSWindow ), y nosotros podríamos escribir una clase propia que herede de
esa. Supongamos que añadimos una característica adicional a nuestra clase. ¿Qué ocurre cuando recibe un mensaje " close "?
Nosotros no hemos escrito código para eso, y tampoco lo hemos copiado de ningún sitio. Es sencillo, si la clase no contiene el
código para un método en particular, el mensaje se transfiere automáticamente a la clase desde la que hemos heredado (conocida
como su "superclase") y si ahí tampoco lo encontrase continuaría buscándolo ascendiendo en la jerarquía de herencia.

Si no se encuentra el método, hemos recibido un mensaje que no podemos gestionar. Es como ir a un taller de coches para que
nos arreglen la lavadora. No nos puede ayudar ni siquiera el jefe del taller. En estos casos Objective-C lanzará un error.

http://www.cocoalab.com/?q=book/export/html/60 Página 32 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Personalización de clases

¿Qué ocurre si queremos implementar un comportamiento distinto para un método que ya existe en la superclase? Es sencillo,
podemos sobreescribir métodos. Por ejemplo, podríamos escribir código para que cuando se pulse el botón para cerrar la
ventana, que la mueva hacia fuera de la pantalla antes de cerrarla. Nuestra clase especial usará el mismo nombre de método que
la clase que definió Apple así que, cuando le llegue el mensaje de cerrar, se ejecutará nuestro código y no el de Apple. Por tanto
ahora la ventana saldrá fuera de la vista antes de cerrarse realmente.

Pero veamos, el código para cerrar la ventana ya lo ha programado Apple, así que desde nuestro método de cerrar ventana
podríamos invocar el método de nuestra superclase. Veamos como hacerlo:
//[2]
- (void) close:(id)sender {
// Aquí escribiríamos el código para desplazar la ventana fuera de la pantalla.
[super close]; // Esto invoca el método "close" de la superclase.
}

Una clase para gobernarlas a todas

La clase que está por encima de todas en la jerarquía de clases es la llamada NSObject . Así que todas clases que nosotros
podamos crear o usar van a ser subclases de NSObject , directa o indirectamente. Por ejemplo la clase NSWindow es una
subclase de NSResponder , que a su vez es subclase de NSObject . La clase NSObject define los métodos comunes a todos los
objetos (por ejemplo, crear una descripción textual del propio objeto, preguntar si el objeto es capaz de entender un mensaje
dado, etc.)

Antes de aburrirte con demasiada teoría veamos como crear una clase.

Creación de una clase


Dentro de nuestro proyecto Xcode seleccionaremos New File dentro del menú File. Seleccionaremos Objective-C Class y
subclass of NSObject. Pulsaremos el botón Next. Llamaremos a la clase "MPAClaseEjemplo". Pulsa el botón Finish.

http://www.cocoalab.com/?q=book/export/html/60 Página 33 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Creación de la clase MPAClaseEjemplo

Después de pulsar Finish verás dos ficheros nuevos en la carpeta Classes del panel Groups & Files: MPAClaseEjemplo.h y
MPAClaseEjemplo.m; si las seleccionas podrás ver su contenido en el editor. En este momento tienen sólo un esqueleto básico.
Recuerda que esta clase la creamos para que reciba los mensajes de los botones y envíe también mensajes al campo de texto.
Vamos a hacer que Interface Builder nos ayude a generar el código.

Las primeras 3 letras de MPAClaseEjemplo vienen de la abreviatura de Mi primera aplicación. Puedes poner a las clases el
nombre que quieras. Pero existe el convenio de que las clases empiecen por una o varias letras mayúsculas y no pueden contener
espacios. Recomendamos que cuando empieces a escribir tus propias aplicaciones elijas 2 o 3 letras mayúsculas para usar como
prefijo en el nombre de tus propias clases. Esto evitará confusiones con las clases existentes. Por ejemplo, no deberías usar NS,
que está reservado para las clases de Apple (NS viene de NeXTStep, que es el sistema operativo en el que se basó Mac OSX
cuando Apple compró la compañía NeXT.

El wiki CocaDev mantiene la lista de prefijos que ya se están usando y, por tanto, deberíamos evitar. Compruébala antes de
elegir tu propio prefijo: http://www.cocoadev.com/index.pl?ChooseYourOwnPrefix.

Cuando se crean clases nuevas debemos elegir un nombre adecuado que proporcione información sobre la clase. Por ejemplo,
ya hemos visto que la clase de Cocoa que representa las ventanas se llama NSWindow . Otro ejemplo podría ser la clase que
representa colores, llamada NSColor . En nuestro caso, la clase MPAClaseEjemplo que estamos creando solamente va a ilustrar
el sistema por el que los objetos se comunican entre ellos en una aplicación. Por eso le damos un nombre genérico sin
significado especial.

Creación de una instancia en Interface Builder


Vuelve a Interface Builder (recuerda que lo abriremos haciendo doble-click en MainMenu.xib). En la ventana Library abre el

http://www.cocoalab.com/?q=book/export/html/60 Página 34 de 59
BecomeAnXcoder-Español 19/05/10 20:25

desplegable superior y selecciona Objects & Controllers. Después arrastra un Object (tiene el icono de un cubo azul) hasta la
clase MainMenu.xib.

Instanciando un nuevo objeto

Después selecciona el botón Identity de la ventana Inspector (Cmd-6) y en la sección Class Identity, en el desplegable Class
selecciona MPAClaseEjemplo. De esta forma instanciaremos nuestra clase MPAClaseEjemplo dentro del fichero xib. Esto
permitirá la comunicación entre nuestro código y la interfaz.

http://www.cocoalab.com/?q=book/export/html/60 Página 35 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Asignando la identidad a nuestro objeto

Creación de conexiones
Nuestro primer paso va a ser crear conexiones entre los botones (que envían mensajes) hacia nuestra clase MPAClaseEjemplo.
Además, crearemos conexiones desde nuestra clase hacia el campo de texto, porque vamos a querer enviar mensajes a ese
componente. Para poder enviar mensajes de un objeto a otro, el primero ha de tener una referencia al segundo, y eso es lo que
conseguiremos creando una conexión.

Veamos lo que queremos que haga la aplicación. Al pulsarse cada botón, tiene que enviar un mensaje. Este mensaje contendrá el
nombre del método de la clase MPAClaseEjemplo que queremos que se ejecute. El mensaje se enviará a la instancia de la clase
MPAClaseEjemplo que acabamos de crear, es decir, un objeto MPAClaseEjemplo. (Recordemos que las instancias no contienen
el código, lo tienen las clases). Por lo tanto el mensaje que llega al objeto MPAClaseEjemplo dispara un método en la clase
MPAClaseEjemplo que hará alguna cosa: en nuestro caso, enviar a su vez un mensaje al campo de texto que creamos en nuestra
ventana de aplicación. Al igual que todo mensaje, éste consiste en el nombre de un método (que tendrá que ejecutar el campo de
texto). En este caso, el método consiste en mostrar un valor, y ese valor será también parte del mensaje (es, por tanto, un
"argumento"; ¿recuerdas el concepto?).

Nuestra clase necesita dos acciones (métodos) que serán llamadas por los objetos botón. Nuestra clase también necesita un
Outlet: una variable para recordar el objeto al que se le va a enviar el mensaje (el campo de texto).

En la ventana Library selecciona, en la parte superior, la pestaña Classes. Esto te mostrará todas las clases y sus atributos del
Framework de Cocoa. En la parte inferior de la ventana hay un campo de búsqueda: comienza a escribir en él el nombre de tu
clase (MPAClaseEjemplo) y la verás aparecer en el primer panel. El aspecto con el que aparece la clase puede ser distinto en tu
ventana. Recuerda que se puede personalizar en el botón de rueda dentada de la parte inferior: aquí está activa la opción "View
icons and descriptions".

http://www.cocoalab.com/?q=book/export/html/60 Página 36 de 59
BecomeAnXcoder-Español 19/05/10 20:25

La clase MPAClaseEjemplo en la librería de clases

Ahora, en la pestaña Actions, haz click en el botón con el signo (+) para añadir una acción (es decir, un método de acción) a la
clase MPAClaseEjemplo. Modifica el nombre que aparece por defecto por otro que tenga más sentido (por ejemplo, puedes
poner "asignarValor5:", ya que en este método haremos que se muestre el número 5 en el campo de texto). Añade también otro
método y dale el nombre "anular:", ya que en este método asignaremos un 0 al campo de texto. Fíjate que el nombre de los
métodos siempre termina en dos puntos (":"). Lo explicaremos después.

http://www.cocoalab.com/?q=book/export/html/60 Página 37 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Creación de métodos en nuestra clase MPAClaseEjemplo

Ahora selecciona la pestaña Outlets, pulsa el botón con el signo (+) para añadir un outlet y dale un nombre, por ejemplo
"campoDeTexto".

http://www.cocoalab.com/?q=book/export/html/60 Página 38 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Creación de un outlet en la clase MPAClaseEjemplo

Antes de crear las conexiones entre objetos, vamos a darle nombres con sentido a nuestros botones. Por ejemplo, ya que el
primero va a hacer que se muestre el valor 5 en el campo de texto, lo vamos a llamar "Asigna valor 5" (recordemos que para
cambiar el nombre, la forma más sencilla es hacer doble-click y escribir el nuevo nombre). De la misma forma, al segundo
botón lo llamaremos "Anular". De todas formas ten en cuenta que lo que acabamos de hacer sólo cumple una función estética y
no es estrictamente necesario para que el programa funcione. Pero debemos hacerlo para que el programa sea lo más descriptivo
posible al usuario final.

Ahora estamos listos para crear las conexiones entre:

1. El botón "Anular" y la instancia de MPAClaseEjemplo


2. El botón "Asigna valor 5" y la instancia de MPAClaseEjemplo
3. La instancia de MPAClaseEjemplo y el campo de texto.

Para crear las conexiones, presiona en el teclado la tecla Ctrl y arrastra el ratón desde el botón "Asigna valor 5" hasta la
instancia de MPAClaseEjemplo en la ventana MainMenu.xib (¡asegúrate de hacerlo en ese sentido y no desde la instancia hacia
el botón!). Mientras nos desplazamos verás una línea que se dibuja. Soltaremos el ratón encima de la instancia y se desplegará
un menú con las acciones que puede recibir la clase. Ahí seleccionaremos "asignarValor5:".

http://www.cocoalab.com/?q=book/export/html/60 Página 39 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Estableciendo la conexión

Ahora el botón mantiene una referencia hacia nuestro objeto MPAClaseEjemplo y le enviará el mensaje asignarValor5:
cuando sea pulsado.

Conecta ahora el botón "Anular" siguiendo el mismo proceso (en el menú que aparece cuando sueltas el ratón encima del objeto
MPAClaseEjemplo deberás seleccionar "anular:").

Para crear la conexión entre MPAClaseEjemplo y el campo de texto, pulsa la tecla Ctrl y empieza a arrastrar desde el objeto
MPAClaseEjemplo y suelta el ratón encima del campo de texto. En el menú que se despliega selecciona "campoDeTexto" (o el
nombre que hayas escogido para el outlet).

¿Para qué ha servido todo esto? Bien, en un momento veremos cómo se creará código sin que hayamos tenido que escribir ni
una sola línea.

Generación del código


Asegúrate de que en la ventana MainMenu.xib está seleccionada nuestra clase MPAClaseEjemplo. Ve al menú File en Interface
Builder y selecciona Write Class Files. Interface Builder preguntará dónde quieres que guarde los ficheros que se van a crear.
No modifiques las opciones que aparecen por defecto, pulsa el botón Save y en la siguiente ventana pulsa Replace.

http://www.cocoalab.com/?q=book/export/html/60 Página 40 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Si vas ahora a Xcode, en la ventana de proyecto deberías ver los ficheros de tu clase en el grupo Classes. Si estuvieran en el
grupo Resources o en otro diferente, basta con que selecciones los dos archivos y los arrastres al grupo Classes. Ahora
selecciona el fichero .h de tu clase para verlo en el editor.

Vemos en nuestro proyecto Xcode los ficheros generados

http://www.cocoalab.com/?q=book/export/html/60 Página 41 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Retrocedamos por un momento al capítulo 3, en el que hablamos de las funciones. ¿Recuerdas la cabecera de la función, como
la que vemos en [11.1]? Es una especie de aviso para el compilador sobre lo que puede esperarse de la función. De los dos
ficheros generados, uno tiene la extensión .h , indicando que es un fichero de cabecera (header en inglés): contiene información
sobre la clase. Por ejemplo, verás que hay una línea [3.3] que contiene NSObject, lo que quiere decir que nuestra clase hereda
de la clase NSObject.
//[3]
// MPAClaseEjemplo.h
#import <Cocoa/Cocoa.h> // [3.2]
@interface MPAClaseEjemplo : NSObject { // [3.3]
IBOutlet id campoDeTexto; // [3.4]
}
- (IBAction)anular:(id)sender; // [3.6]
- (IBAction)asignarValor5:(id)sender; // [3.7]
@end

Verás que hay un outlet [3.4] que apunta al objeto campo de texto. id indica objeto. "IB" se refiere a Interface Builder, el
programa que hemos usado para crear este código.

IBAction [3.6, 3.7] es equivalente a void . No se devuelve nada al objeto que envía un mensaje: los botones de nuestro
programa no obtienen una respuesta de nuestro objeto MPAClaseEjemplo al que envían su mensaje.

Verás también que hay dos acciones de Interface Builder (IBAction). Son dos métodos de nuestra clase. Los métodos son
bastante parecidos a las funciones pero hay algunas diferencias que veremos más adelante.

Anteriormente hemos visto #import <Foundation/Foundation.h> en lugar de la línea [3.2]. La primera (Foundation) es
para aplicaciones de consola (sin interfaz gráfica) y ésta (Cocoa) es para aplicaciones con GUI (Interfaz Gráfica de Usuario).

Ahora comprobemos el segundo fichero, el que tiene la extensión .m


//[4]
// MPAClaseEjemplo.m
#import "MPAClaseEjemplo.h" // [4.2]
@implementation MPAClaseEjemplo
- (IBAction)anular:(id)sender { //[4.4]
}
- (IBAction)asignarValor5:(id)sender {
}
@end

Antes de nada, vemos que hay una instrucción [4.2] para importar el fichero de cabecera. Podemos reconocer dos métodos:
anular: and asignarValor5: . Esos son los métodos de nuestra clase. Se parecen a las funciones en que su código debe
escribirse entre llaves. En nuestra aplicación, cuando se presiona un botón, éste envía un mensaje al objeto MPAClaseEjemplo,
requiriendo la ejecución de uno de los métodos. No hemos tenido que escribir código para ese comportamiento, sólo hemos
tenido que crear las conexiones en Interface Builder. Pero ahora tenemos que implementar los dos métodos, es decir, escribir el
código que queremos que se ejecute dentro de cada uno. En nuestro caso queremos que envíen un mensaje al campo de texto, lo
que conseguiremos escribiendo las líneas [5.4, 5.7].
//[5]
#import "MPAClaseEjemplo.h"
@implementation MPAClaseEjemplo
- (IBAction)anular:(id)sender {
[campoDeTexto setIntValue:0]; // [5.4]
}
- (IBAction)asignarValor5:(id)sender {
[campoDeTexto setIntValue:5]; // [5.7]
}
@end

Recomendamos volver un instante al comienzo de esta lección, donde en [1] veíamos el formato de las instrucciones para
enviar mensajes. Como puedes ver, enviamos un mensaje al objeto referido en el outlet campoDeTexto . Al haber conectado
mediante Interface Builder este outlet con el campo de texto, el mensaje se enviará al objeto correcto. El mensaje contiene el
nombre de un método, setIntValue: , junto a un valor numérico entero. El método setIntValue: tiene la capacidad de
mostrar un valor entero en un objeto de campo de texto. En el siguiente capítulo veremos como hemos averiguado la
información sobre este método.

http://www.cocoalab.com/?q=book/export/html/60 Página 42 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Listo para despegar


Ahora lo tienes todo listo para compilar tu aplicación y ejecutarla. Como ya sabes, pulsa el botón Build and Run. Xcode tardará
unos segundos en compilar la aplicación y después la ejecutará: aparecerá la ventana de tu aplicación y podrás probarla.

Nuestra aplicación funcionando

Hemos creado con unos pocos pasos una aplicación (eso sí, muy básica), en la que sólo hemos tenido que escribir dos líneas de
código

09: Búsqueda de métodos


Introducción
En el capítulo anterior escribimos el cuerpo de dos métodos por nosotros mismos, pero también usamos un método de los que
proporciona Apple, setIntValue: , que usamos para mostrar el valor de un número entero en un objeto campo de texto.
¿Cómo podemos conocer qué métodos hay disponibles?

Recuerda que para cada método que uses de los que proporciona Apple, no tendrás que escribir código propio, con lo que hay
menos posibilidad de que aparezcan errores. Así que siempre vale la pena dedicar tiempo a conocer los métodos que están ya a
nuestra disposición antes de escribirlos por nosotros mismos.

Ejercicio
En Interface Builder, al seleccionar un objeto en la ventana "Library" (la que tiene una paleta con todos los objetos disponibles),
en la parte inferior de esa ventana, debajo de su nombre descriptivo, aparece el nombre de su clase. Por ejemplo si seleccionas
el objeto botón que empleamos en nuestra primera aplicación leerás "NSButton" y si seleccionas el campo de texto (es el que
tiene el texto "Label") verás "NSTextField". Vamos a comprobar qué métodos tiene disponible NSTextField .

Vamos a Xcode y dentro del menú Help seleccionamos "Developer documentation". En el campo de búsqueda de la parte
superior derecha empieza a escribir NSTextField. Según lo vas escribiendo, el panel izquierdo de la ventana muestra los
resultados que coinciden con el texto y en el panel derecho aparece la información relativa al primero de esos resultados. Puedes
dejar de escribir en cuanto veas en el panel izquierdo la clase NSTextField.

http://www.cocoalab.com/?q=book/export/html/60 Página 43 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Navegando por la documentación de Xcode.

En lo primero que deberías fijarte es en la jerarquía de clases (en la sección con el texto Inherits from). La que está más a la
derecha es, como ya comentamos en el capítulo anterior, la clase padre de todas: NSObject . Si te desplazas hacia abajo en el
documento encontrarás el encabezado:

Instance Methods

Vamos a empezar aquí la búsqueda. Si echamos un vistazo a los métodos disponibles nos damos cuenta de que no parece haber
ninguno para asignar un valor al campo de texto. Tendremos que desplazarnos a la clase superior para buscarlo allí. Según
pudimos ver en la jerarquía de clases, la clase inmediatamente superior a NSTextField es NSControl . Como la
documentación está en HTML hay hipervínculos, así que si hacemos click sobre NSControl en la vista de jerarquía de clases,
aparecerá la página de la clase NSControl .

Desplazándonos hacia abajo por el documento encontramos el encabezado:

Tasks (Tareas)

y más abajo

Setting the control's value (Asignar un valor al control)

Eso es lo que queremos. Ahí encontramos el método:

- setIntValue:

Eso suena bien, así que hacemos click en el nombre del método para que nos lleve a su documentación.

setIntValue:

Sets the value of the receiver’s cell using an integer.

http://www.cocoalab.com/?q=book/export/html/60 Página 44 de 59
BecomeAnXcoder-Español 19/05/10 20:25

- (void)setIntValue:(int)anInt

Parameters

anInt

The value of the cell interpreted as an integer.

Discussion

If the cell is being edited, this method aborts all editing before setting the value. If the cell does not inherit from NSActionCell,
the method marks the cell’s interior as needing to be redisplayed; NSActionCell performs its own updating of cells.

En nuestra aplicación, el objeto NSTextField es el receptor y tenemos que pasarle un entero. Esto lo podemos también
comprobar en la firma del método:
- (void)setIntValue:(int)anInt

En Objective-C, el signo menos (-) al comienzo indica que se trata de un método de instancia (opuesto a un método de clase, del
que hablaremos más adelante). void indica que no se devuelve nada al que invoca el método. Después de los dos puntos, (int)
indica que la variable anInt debe ser un número entero. En nuestro ejemplo hemos invocado este método pasándole un 5 y un 0
así que lo hemos hecho correctamente.

No siempre es tan fácil encontrar el método que se ajusta a lo que estamos buscando. Esto se te dará mejor cuanto más uses la
ayuda, así que sigue practicando.

¿Y cómo harías para leer el valor que hay en nuestro objeto campoTexto ? ¿Recuerdas en la lección sobre funciones la
característica de que todas las variables en su interior están aisladas del exterior? Lo mismo sucede con los métodos. Por ello
los objetos suelen tener un par de métodos relacionados llamados "Accessors": uno para leer el valor y otro para asignarlo. Ya
conocemos el último: setIntValue: . El primero tiene este aspecto:

//[1]
- (int) intValue

Como puedes ver en su firma, este método devuelve un entero. Así que si queremos leer el valor entero contenido en nuestro
campo de texto deberíamos enviar un mensaje como este:
//[2]
int resultadoRecibido = [campoTexto intValue];

De nuevo, en funciones (y en métodos) todas las variables están aisladas. Eso es bueno para los nombres de variables, porque
no hay que preocuparse de que al asignar un valor a una variable en una parte de nuestro programa, esto afecte a una variable
con el mismo nombre dentro de otra función. Sin embargo, los nombres de funciones sí que deben ser únicos en nuestro
programa. Objective-C va un paso más allá: los nombres de métodos debe ser únicos en la misma clase, pero clases distintas
puede compartir nombres de métodos. Esto es una característica importante para escribir programas grandes, ya que los
programadores pueden escribir cada uno sus clases sin preocuparse de que haya conflictos con los nombres de métodos de las
clases que escriban los demás.

Pero hay más. Se llama polimorfismo al hecho de que clases diferentes puedan tener los mismos nombres de métodos y es una
de las cosas que hacen tan especial la programación orientada a objetos: te permite escribir trozos de código sin que tengas que
conocer previamente las clases de los objetos sobre las que se va a aplicar ese código. Lo único que se requiere es que, en el
momento de la ejecución del programa, los objetos comprendan los mensajes que se les envían.

Aprovechando el polimorfismo podemos escribir aplicaciones flexibles y extensibles. Por ejemplo, en la aplicación GUI que
hemos creado, si reemplazásemos el campo de texto por otro objeto de cualquier clase capaz de comprender el mensaje
setIntValue: la aplicación seguiría funcionando sin tener que modificar el código, ni siquiera haría falta recompilarla.
Incluso tenemos la capacidad de hacer el cambio de objeto en tiempo de ejecución sin romper nada. Ahí reside el poder de la
programación orientada a objetos.

10: awakeFromNib
Introducción
Apple ha realizado un montón de trabajo por ti, facilitando la creación de tus programas. En tu pequeña aplicación no has

http://www.cocoalab.com/?q=book/export/html/60 Página 45 de 59
BecomeAnXcoder-Español 19/05/10 20:25

tenido que preocuparte de dibujar la ventana ni los botones, además de muchas otras cosas.

La mayor parte de ese trabajo reside en dos entornos de trabajo (frameworks). El Foundation Kit que importamos en el ejemplo
[11] del capítulo 4 aporta la mayoría de los servicios que no están asociados al interfaz gráfico de usuario. El otro framework,
llamado Application Kit, trata con los objetos que ves en pantalla y los mecanismos de interacción con el usuario. Ambos están
bien documentados.

Vayamos a la aplicación GUI que montamos en el capítulo 8. Supongamos que queremos mostrar un valor en el campo de texto
en el momento en que se lanza la aplicación y se muestra la ventana.

Ejercicio
Toda la información de la ventana se almacena en un fichero nib (nib viene de NeXT Interface Builder). Esto es un buen
indicador de que el método que necesitamos debe ser parte del Application Kit. Veamos como obtener información sobre este
marco de trabajo.

En Xcode, ve al menú Help y selecciona Developer Documentation. En el campo de búsqueda (arriba a la derecha) escribe
Application Kit.

Veremos múltiples resultados en el panel izquierdo, entre ellos un documento titulado "Application Kit Framework Reference";
haremos click en esa línea para que se abra el documento en el panel principal de la ventana de ayuda. En ese documento, bajo
el encabezado "Protocol References" encontraremos un enlace con el texto NSNibAwaking . Al hacer click ahí se abrirá la
documentación de la clase NSNibAwaking .

NSNibAwaking Protocol Reference

(informal protocol)

Framework /System/Library/Frameworks/AppKit.framework

Companion document Resource Programming Guide

Declared in NSNibLoading.h

Overview

This informal protocol consists of a single method, awakeFromNib. Classes can implement this method to initialize state
information after objects have been loaded from an Interface Builder archive (nib file).

Este protocolo consiste en un solo método, awakeFromNib. Las clases pueden implementar este método para inicializar su
información de estado una vez que se han cargado los objetos desde un archivo de Interface Builder (fichero nib).

Si implementamos este método, será llamado cuando nuestro objeto se haya terminado de cargar desde el archivo nib. Así que
podemos utilizarlo para conseguir nuestro objetivo: mostrar un valor en el campo de texto en el momento en el arranca el
programa.

No quiero sugerir que sea siempre fácil encontrar el método que estamos buscando. Frecuentemente requerirá bastante
indagación y un uso adecuado de las palabras de búsqueda. Por esa razón es muy importante que te familiarices con la
documentación de ambos frameworks, así te harás una idea de los métodos que tienes disponibles. Puedes no necesitarlo en este
momento, pero te ayudará a hacerte una idea de como conseguir que tu programa haga lo que quieres.

Bien, hemos encontrado nuestro método, todo lo que necesitamos es añadirlo a nuestro fichero de implementación
MPAClaseEjemplo.m [1.9].

//[1]
#import "MPAClaseEjemplo.h"
@implementation MPAClaseEjemplo

http://www.cocoalab.com/?q=book/export/html/60 Página 46 de 59
BecomeAnXcoder-Español 19/05/10 20:25

- (IBAction)anular:(id)sender {
[campoDeTexto setIntValue:0];
}
- (IBAction)asignarValor5:(id)sender {
[campoDeTexto setIntValue:5];
}
- (void)awakeFromNib { // [1.9]
[campoDeTexto setIntValue:0];
}
@end

Cuando se abra la ventana, se llamará automáticamente al método awakeFromNib . Como resultado el campo de texto mostrará
un cero, que es lo que hemos codificado en el cuerpo del método.

11: Punteros
¡Aviso!
Este capítulo contiene conceptos avanzados y trata con elementos del lenguaje C que pueden intimidar a los principiantes. Si no
los comprendes ahora, no te preocupes. Por suerte, aunque es útil comprender cómo funcionan los punteros, no es esencial para
empezar a programar con Objective-C.

Introducción
Cuando se declara una variable, el Mac asocia esa variable con una zona de la memoria en la que va a almacenar su valor.

Veamos, por ejemplo, la siguiente instrucción:


//[1]
int x = 4;

Para poder ejecutarla, tu Mac busca espacio libre en su memoria y después toma nota de que ese espacio es donde va a
almacenar el contenido de la variable x (por supuesto deberíamos haber usado un nombre más descriptivo para esa variable).
Mira la instrucción [1] de nuevo. Al indicar el tipo de variable (en este caso int ) le hacemos saber al ordenador cuanto espacio
se necesita para almacenar su valor. Si la variable fuese de tipo long long o double requeriría más espacio de
almacenamiento.

La instrucción de asignación x = 4 almacena el número 4 en su espacio reservado. Por supuesto el ordenador recuerda en qué
parte de su memoria está almacenado el valor de la variable x o, en otras palabras, cuál es la dirección de la variable x . De esta
forma, cada vez que usas x en tu programa, el ordenador va al lugar correcto (la dirección correcta) a recoger el valor de x .

Un puntero es sencillamente una variable que contiene la dirección de otra variable.

Referenciar variables
Dada una variable, puedes obtener su dirección escribiendo & antes de su nombre. Por ejemplo, para obtener la dirección de x ,
escribirías &x .

Cuando el ordenador evalúa la expresión x devuelve su valor (en nuestro caso obtenemos 4 ). Sin embargo cuando evalúa la
expresión &x , devuelve la dirección de x , no el valor almacenado ahí. La dirección es un número que indica un lugar específico
en la memoria del ordenador (igual que un número de habitación indica una habitación específica en un hotel).

Uso de punteros
Los punteros se declaran así:
//[2]
int *y;

Esta instrucción define una variable llamada y que contendrá la dirección de una variable de tipo int . Repetimos: no va a
contener un variable de tipo int , sino la dirección de esa variable. Para almacenar en la variable y la dirección en la que está
almacenado el contenido de la variable x (para almacenar en y la dirección de x ), escribiríamos:

http://www.cocoalab.com/?q=book/export/html/60 Página 47 de 59
BecomeAnXcoder-Español 19/05/10 20:25

//[3]
y = &x;

Ahora y "apunta a" la dirección de x , por tanto podemos usar y para localizar x . Veamos como:

Dado un puntero, podemos obtener la variable a la que apunta escribiendo un asterisco (*) delante del puntero. Por ejemplo, al
evaluar la expresión:
*y

obtendremos en este caso 4 . Esto es equivalente a evaluar la expresión x . Y la siguiente instrucción:

*y = 5

es equivalente a:

x = 5

Los punteros son útiles porque a veces no quieres trabajar con el valor de una variable sino con su dirección. Por ejemplo, si
queremos programar una función que incremente en 1 el valor de una variable, ¿podrías resolverlo de la siguiente forma?

//[4]
void incrementa(int x)
{
x = x + 1;
}

Realmente, no. Si llamas a esta función desde un programa, no obtendrías el resultado que esperas:

//[5]
int miValor = 6;
incrementa(miValor);
NSLog(@"%d:\n", miValor);

Este código mostraría 6 en tu pantalla ¿Adivinas por qué? ¿Has incrementado miValor al llamar a la función? No, no lo has
hecho. Como puedes ver, la función recoge el valor que se le ha pasado en miValor , es decir, el número 6 , le suma 1 y …, se
deshace de él. Las funciones sólo trabajan con los valores que se les pasan, no con las variables que contienen esos valores. Por
tanto las modificaciones producidas dentro de la función se pierden cuando se sale de la función. Es más, imaginemos que no
pasamos una variable, podríamos pasar directamente un valor; si llamásemos a la función con incrementa(5); ¿qué es lo que
esperamos que se incremente?

Así que si esperas una función de incremento que realmente funcione, es decir, que acepte una variable como argumento y que
realmente incremente el valor contenido en esa variable, vas a necesitar pasar la dirección de esa variable. De esa forma podrás
modificar lo que está contenido en esa variable. Por tanto la solución está en pasar como argumento un puntero:
//[6]
void incrementa(int *y)
{
*y = *y + 1;
}

Y tendrías que llamar a la función así:


[7]
int miValor = 6;
incrementa(&miValor); // pasamos la dirección
// Ahora miValor contiene el valor 7

12: Cadenas de caracteres


Introducción
Hasta ahora hemos visto varios tipos de datos básicos: int, long, float, double, BOOL . Y en el anterior capítulo hemos
presentado los punteros. Aunque hemos usado cadenas de caracteres, sólo lo hicimos con respecto a la función NSLog() . Esta
función nos permite enviar una cadena a la pantalla, reemplazando los códigos que empiezan por el signo (%), como por
ejemplo %d , por un valor (repasar si es necesario el capítulo 4).

//[1]

http://www.cocoalab.com/?q=book/export/html/60 Página 48 de 59
BecomeAnXcoder-Español 19/05/10 20:25

float valorDePi = 3.1416;


NSLog(@"Esto son tres ejemplos de impresión en pantalla de cadenas de caracteres.\n");
NSLog(@"Pi se aproxima a %10.4f.\n", valorDePi);
NSLog(@"El número de caras de un dado es %d.\n", 6);

No hemos hablado antes de las cadenas por una buena razón. A diferencia de int o float , las cadenas son verdaderos objetos,
creados a partir de la clase NSString o de la clase NSMutableString . Vamos a conocer estas clases, empezando por
NSString .

NSString
De nuevo con los punteros
//[2]
NSString *ordenadorFavorito; // [2.1]
ordenadorFavorito = @"¡Mac!";
NSLog(ordenadorFavorito);

Probablemente entiendas la segunda línea, pero la primera requiere alguna explicación. ¿Recuerdas que, cuando declaramos una
variable puntero, debemos indicar a qué tipo de dato apunta? Repasemos la sentencia del capítulo 11.

//[3]
int *y;

Aquí indicamos que la variable puntero y contiene la dirección de una zona de memoria en la que se puede encontrar un entero.

En [2.1] le indicamos al compilador que la variable puntero ordenadorFavorito contiene la dirección de memoria en la que
se puede encontrar un objeto de tipo NSString . Usamos un puntero para guardar nuestra cadena porque en Objective-C lo
objetos no se manipulan directamente, sino siempre a través de punteros a dichos objetos.

No te preocupes demasiado si no comprendes esto, no es crucial. Lo que sí debes recordar es referirte siempre a una instancia de
NSString o NSMutableString (o cualquier otro objeto) usando el asterisco (*).

El símbolo @
¿Por qué vemos siempre el signo @ delante de la cadenas de caracteres? Bien, Objective-C es una extensión del lenguaje C, que
tiene su propia forma de tratar con cadenas. Para diferenciar el nuevo tipo de cadenas, que son objetos en toda su extensión,
Objective-C coloca delante un signo @.

Un nuevo tipo de cadena


¿En qué mejoran las cadenas de Objective-C con respecto a las de C? En primer lugar las cadenas de Objective-C son Unicode
en lugar de ASCII, lo que implica que pueden representar caracteres de cualquier lenguaje, por ejemplo el chino, además de, por
supuesto, nuestro alfabeto.

Ejercicio
Podemos, en una sola instrucción, declarar y asignar valor a una cadena[4].

//[4]
NSString *actrizFavorita = @"Julia";

La variable puntero actrizFavorita apunta a la posición de memoria en la que se aloja el objeto que contiene la cadena
"Julia".

Una vez que se le ha dado un valor a la cadena, se le podría asignar otro valor, pero no se puede modificar la propia cadena
[5.7], porque es una instancia de la clase NSString . Enseguida aclaramos esto.
//[5]
#import <foundation/foundation.h>
int main (int argc, const char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *ordenadorFavorito;
ordenadorFavorito = @"iBook"; // [5.7]
ordenadorFavorito = @"MacBook Pro";

http://www.cocoalab.com/?q=book/export/html/60 Página 49 de 59
BecomeAnXcoder-Español 19/05/10 20:25

NSLog(@"%@", ordenadorFavorito);
[pool release];
return 0;
}

Cuando se ejecuta, el programa imprime:

MacBook Pro

La cadena no se puede modificar, pero lo que sí se puede hacer (y de hecho acabamos de hacerlo) es reemplazar la cadena por
otra.

NSMutableString
A una cadena de la clase NSString la llamamos inmutable, porque no se puede modificar. Lo que esto significa es que no se
pueden alterar los caracteres individuales del texto que la compone.

¿Y qué tiene de bueno una cadena que no se puede modificar? Bien, la ventaja es que son más fáciles de manejar por el sistema
operativo, así que el programa correrá más rápido. Además verás que cuando hagas tus propios programas, encontrarás pocas
ocasiones en las que necesites modificar cadenas.

Por supuesto, hay veces en que necesitas modificar las cadenas, y para eso tenemos la clase NSMutableString . La vamos a ver
más adelante en este capítulo.

Ejercicio
Antes quiero asegurarme de que comprendes que las cadenas son objetos. Si son objetos, entonces podemos enviarles mensajes.
Por ejemplo, vamos a enviar el mensaje "length" (longitud) a un objeto cadena [6].

//[6]
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int longitud;
NSString * foo;
foo = @"¡Julia!";
longitud = [foo length]; // [6.10]
NSLog(@"La longitud es %d.", longitud);
[pool release];
return 0;
}

Cuando se ejecuta, este programa muestra:


La longitud es 7.

Con frecuencia vas a encontrar en documentos en inglés que los programadores tienen la costumbre de llamar foo y bar a las
variables de sus ejemplos. Realmente se consideran nombres no apropiados ya que no son descriptivos, igual que pasa con el
nombre de variable x . Los usamos aquí para que los conozcas cuando los encuentres en otros ejemplos por internet.

En la línea [6.10] enviamos el mensaje length al objeto foo . Este método está definido así en la clase NSString :

- (unsigned int)length

Returns the number of Unicode characters in the receiver. (devuelve el número de caracteres Unicode del receptor.

Podrías también querer cambiar el texto a mayúsculas [7]. El mensaje que tendrías que enviar es entonces uppercaseString ,
que también podrías encontrar por ti mismo en la documentación (lee los métodos de instancia disponibles para la clase
NSString ). Al recibir este mensaje, el objeto devuelve otro objeto NSString con el mismo contenido pero con cada carácter
convertido a mayúscula.
//[7]
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{

http://www.cocoalab.com/?q=book/export/html/60 Página 50 de 59
BecomeAnXcoder-Español 19/05/10 20:25

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];


NSString *foo, *bar;
foo = @"¡Julia!";
bar = [foo uppercaseString];
NSLog(@"%@ se converte a %@.", foo, bar);
[pool release];
return 0;
}

Si lo ejecutas, mostrará:

¡Julia! se converte a ¡JULIA!

A veces podrías querer modificar el contenido de una cadena en lugar de crear una nueva. En tal caso tendrías que alojar tu
texto en un objeto de la clase NSMutableString , que trae varios métodos para modificar el contenido. Por ejemplo, el método
appendString: añade la cadena pasada como argumento al final del receptor.

//[8]
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableString *foo; // [8.5]
foo = [@"¡Julia!" mutableCopy]; // [8.6]
[foo appendString:@" estoy feliz"];
NSLog(@"Aquí está el resultado: %@.", foo);
[pool release];
return 0;
}

Cuando se ejecute, el programa mostrará:


Aquí está el resultado: ¡Julia! estoy feliz.

En la línea [8.6] el método mutableCopy (que está disponible en la clase NSString ) crea y devuelve una cadena modificable
con el mismo contenido que el receptor del mensaje. Así que después de la ejecución de la línea [8.6], la variable foo apunta a
un objeto de cadena modificable que contiene el texto "¡Julia!".

De nuevo más punteros


Comentamos al comienzo del capítulo que en Objective-C no se usan los objetos directamente sino que siempre se referencian
mediante punteros a ellos. Y esa es la razón por la que usamos la notación de puntero en la línea [8.5]. Realmente, cuando
usamos la palabra "objeto" en Objective-C lo que queremos decir es "puntero a un objeto". Pero como siempre accedemos a los
objetos mediante punteros se ha terminado abreviando simplemente con la palabra "objeto". El hecho de que siempre se usen
mediante punteros tiene una implicación importante que debemos conocer: más de una variable pueden referenciar el mismo
objeto al mismo tiempo. Por ejemplo, después de la línea [8.6] la variable foo referencia a un objeto que representa la cadena
"¡Julia!", algo que podríamos representar con el siguiente diagrama:

Los objetos siempre se usan mediante punteros

Ahora supongamos que asignamos el valor de foo a la variable bar de esta forma:

bar = foo;

El resultado de esto es que tanto foo como bar apuntan al mismo objeto:

http://www.cocoalab.com/?q=book/export/html/60 Página 51 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Múltiples variables pueden referenciar el mismo objeto

En esta situación, enviar un mensaje a foo (por ejemplo [foo length]; ) tiene el mismo efecto que enviar un mensaje a bar
(por ejemplo [bar length]; ), tal como se muestra en el siguiente ejemplo:

//[9]
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableString *foo = [@"¡Julia!" mutableCopy];
NSMutableString *bar = foo;
NSLog(@"foo apunta a la cadena: %@.", foo);
NSLog(@"bar apunta a la cadena: %@.", bar);
NSLog(@"\n");
[foo appendString:@" estoy feliz"];
NSLog(@"foo apunta a la cadena: %@.", foo);
NSLog(@"bar apunta a la cadena: %@.", bar);
[pool release];
return 0;
}

Cuando se ejecuta el programa, muestra:

foo apunta a la cadena: ¡Julia!.


bar apunta a la cadena: ¡Julia!.
foo apunta a la cadena: ¡Julia! estoy feliz.
bar apunta a la cadena: ¡Julia! estoy feliz.

El poder tener referencias al mismo objeto desde diferentes lugares al mismo tiempo es una característica esencial de los
lenguajes orientados a objetos. Realmente ya lo habíamos usado previamente. Por ejemplo, en el capítulo 8, referenciamos el
objeto MPAClaseEjemplo desde dos objetos botón diferentes.

13: Arrays
Introducción
A veces necesitas manejar conjuntos de datos. Por ejemplo podrías necesitar tener una lista de cadenas de texto. Podría ser
bastante molesto usar una variable para cada una de esas cadenas. Por supuesto hay una solución mejor: el array.

Un array es una lista ordenada de objetos (o, más exactamente, una lista de punteros a objetos). Puedes añadir objetos al array,
eliminarlos o preguntarle qué objeto está almacenado en determinado índice (es decir, en una determinada posición). También
puedes preguntarle cuántos elementos contiene.

Cuando contamos elementos, generalmente comenzamos a contar por 1. Pero en los arrays el primer elemento tiene el índice 0,
el segundo tiene índice 1 y así sucesivamente.

http://www.cocoalab.com/?q=book/export/html/60 Página 52 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Ejemplo: un array que contiene tres strings

Más tarde veremos ejemplos de código, que nos permitirán entender el efecto de empezar a contar por 0.

Tenemos dos clases para manejar arrays: NSArray y NSMutableArray . Igual que con las cadenas, hay una versión mutable y
una inmutable. En este capítulo vamos a usar la versión mutable.

Éstos son arrays exclusivos de Objective-C y Cocoa. Hay también un tipo simple de array propio del lenguaje C (y por tanto
también parte de Objective-C) del que no vamos a hablar aquí. Te lo advertimos por si más tarde lees algo sobre los arrays de C,
que no tienen nada que ver con las clases NSArray y NSMutableArray .

Un método de clase
Una forma de crear un array es ejecutar una instrucción como esta:

[NSMutableArray array];

Esto creará y devolverá un array vacío. Pero… espera un minuto… esto es extraño, ¿no? Estamos usando una clase
(NSMutableArray) como receptora de un mensaje y hasta ahora siempre habíamos enviado mensajes a instancias (es decir, a
objetos), no a clases.

Bien, pues acabamos de aprender algo nuevo: el hecho de que también podemos llamar a métodos de las clases (y eso se debe a
que las clases son también objetos, instancias de lo que se llaman metaclases, pero no vamos a ir más allá en este artículo de
introducción).

No tenemos que preocuparnos de liberar la memoria ocupada al alojar este objeto, ya que se produce automáticamente por estar
vinculado a un NSAutoreleasePool (ver el código que se genera automáticamente relativo al NSAutoreleasePool en
nuestros programas Xcode). Al llamar al método de clase estamos haciendo algo equivalente a:
NSMutableArray *lista = [[[NSMutableArray alloc] init] autorelease];

En caso de que quisieras que el array permaneciera en memoria después de que se libere el objeto NSAutoreleasePool
deberías enviar un mensaje -retain a la instancia.

En la documentación de Cocoa, los métodos de clase están precedidos de un símbolo "+", en lugar del símbolo "-" que hemos
visto hasta ahora para los métodos de instancia (ver por ejemplo el capítulo 8, [4.4]). Por ejemplo, en la documentación del
método "array" leemos:

array

+ (id)array

Creates and returns an empty array. This method is used by mutable subclasses of NSArray. See Also: + arrayWithObject:, +
arrayWithObjects:

Ejercicio
Vamos a escribir código. El siguiente programa crea un array vacío, almacena en él tres cadenas y después muestra el número
de elementos en el array.

//[1]
#import <foundation/foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *miArray = [NSMutableArray array];
[miArray addObject:@"primera cadena"];

http://www.cocoalab.com/?q=book/export/html/60 Página 53 de 59
BecomeAnXcoder-Español 19/05/10 20:25

[miArray addObject:@"segunda cadena"];


[miArray addObject:@"tercera cadena"];
int cantidad = [miArray count];
NSLog(@"Hay %d elementos en mi array", cantidad);
[pool release];
return 0;
}

Cuando se ejecute, este programa mostrará:

Hay 3 elementos en mi array

El siguiente programa es como el anterior excepto que muestra la cadena almacenada en el índice 0 del array. Para obtenerla,
usaremos el método objectAtIndex: [2.9].

//[2]
#import <foundation/foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *miArray = [NSMutableArray array];
[miArray addObject:@"primera cadena"];
[miArray addObject:@"segunda cadena"];
[miArray addObject:@"tercera cadena"];
NSString *elemento = [miArray objectAtIndex:0]; // [2.9]
NSLog(@"El elemento en el índice 0 del array es: %@", elemento);
[pool release];
return 0;
}

Cuando se ejecute, mostrará:

El elemento en el índice 0 del array es: primera cadena

A veces tienes que recorrer un array para hacer algo con cada uno de sus elementos. Para ello puedes usar un bucle como el que
mostramos a continuación, en el que mostramos cada elemento del array además de su índice:

//[3]
#import <foundation/foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *miArray = [NSMutableArray array];
[miArray addObject:@"primera cadena"];
[miArray addObject:@"segunda cadena"];
[miArray addObject:@"tercera cadena"];
int i;
int cantidad;
for (i = 0, cantidad = [miArray count]; i < cantidad; i = i + 1)
{
NSString *elemento = [miArray objectAtIndex:i];
NSLog(@"El elemento en el índice %d del array es: %@", i, elemento);
}
[pool release];
return 0;
}

Cuando se ejecute, el programa mostrará:

El elemento en el índice 0 del array es: primera cadena


El elemento en el índice 1 del array es: segunda cadena
El elemento en el índice 2 del array es: tercera cadena

Ten en cuenta que los arrays no están limitados a contener cadenas. Pueden contener cualquier objeto que quieras.

Las clases NSArray y NSMutableArray proporcionan otros muchos métodos, y recomendamos que mires la documentación de
estas clases para aprender más sobre arrays. Terminaremos este capítulo hablando del método que permite reemplazar un objeto
por otro en un índice determinado. Este método se llama replaceObjectAtIndex:withObject:.

Hasta ahora hemos utilizado métodos que requieren como mucho un argumento. Pero éste es diferente porque necesita dos

http://www.cocoalab.com/?q=book/export/html/60 Página 54 de 59
BecomeAnXcoder-Español 19/05/10 20:25

argumentos, tal como puedes advertir al tener dos caracteres "dos puntos (:)" en el nombre del método. Vamos a ver cómo usar
este método:

//[4]
[miArray replaceObjectAtIndex:1 withObject:@"Hola"];

Después de la ejecución, en el índice 1 estará la cadena @"Hola" . Por supuesto sólo se debe llamar a este método con un índice
válido, es decir, debe haber ya un objeto en ese índice para que pueda ser sustituido por el objeto que le pasamos.

Conclusión
Como puedes ver, los nombres de métodos en Objective-C son como instrucciones con espacios vacíos en medio (precedidos
del carácter "dos puntos"). Cuando invocas al método debes insertar el valor en esos espacios, creando una instrucción llena de
sentido. Esta sintaxis de nombre e invocación de métodos viene del lenguaje Smalltalk y es uno de los logros más importantes
de Objective-C, ya que hace el código muy expresivo. Cuando crees tus propios métodos deberías recordar llamarlos de forma
que crees una instrucción con pleno significado cuando se llamen. Esto hará el código más legible, lo que facilitará el
mantenimiento posterior de los programas.

14: Accessors y propiedades


Introducción
Hemos visto que un objeto puede ser visible, por ejemplo una ventana o un campo de texto; o invisible, como un array o un
controlador que responde a acciones del interfaz de usuario. Así que ¿qué es exactamente un objeto?

En esencia un objeto consta de una serie de valores (lo que llamamos variables) y realiza algunas acciones (lo que llamamos
métodos). Un objeto contiene y transforma datos. Podemos concebir un objeto como un pequeño ordenador, que envía y
responde a mensajes. Tu programa sería una especie de red en la que todos esos pequeños ordenadores trabajan juntos para
producir el resultado deseado.

Composición de objetos
El trabajo de un programador Cocoa es crear clases que contengan otros objetos (como cadenas de texto, arrays y diccionarios)
en los que se almacenan los valores que necesita la clase para hacer su trabajo. Algunos de esos objetos se crearán, usarán y
destruirán aisladamente dentro de un método. Pero otros será necesario que permanezcan durante todo el ciclo de vida del
objeto. A estos últimos objetos se les llama variables de instancia o propiedades de la clase. La clase puede también definir
métodos que trabajen con estas variables.

A esta técnica se le llama composición de objetos. Estos objetos compuestos generalmente heredan directamente de NSObject .

Por ejemplo, una clase controladora de una calculadora podría contener como variables de instancia: un array de objetos botón y
un campo de texto para el resultado. También podría contener métodos para sumar, restar, multiplicar y dividir números y
mostrar el resultado en el GUI.

Las variables de instancia de declaran en el fichero de cabecera de la clase. En el ejemplo de nuestra calculadora sería algo así:

//[1]
@interface MiControladorDeCalculadora : NSObject {
//Variables de instancia
NSArray * botones;
NSTextField * campoResultado;
}
//Métodos
- (NSNumber *)mutiplica:(NSNumber *)valor;
- (NSNumber *)suma:(NSNumber *)valor;
- (NSNumber *)resta:(NSNumber *)valor;
- (NSNumber *)divide:(NSNumber *)valor;
@end

Encapsulación
Uno de los objetivos de la programación orientada a objetos es la encapsulación: hacer cada clase lo más autocontenida y
reutilizable posible. Si recordamos el capítulo 3, las variables dentro de bucles, funciones y métodos están aisladas del exterior.

http://www.cocoalab.com/?q=book/export/html/60 Página 55 de 59
BecomeAnXcoder-Español 19/05/10 20:25

Este aislamiento también vale para los objetos. Esto significa que desde el exterior no podemos acceder a las variables de
instancia de otros objetos, no están disponibles nada más que para los propios métodos de la clase.

Pero a veces necesitamos desde otros objetos modificar las variables de instancia de un objeto. ¿Cómo hacerlo?

Los métodos sí están disponibles desde fuera de un objeto. Todo lo que tenemos que hacer es enviar un mensaje al objeto para
disparar ese método. Así que para tener disponible determinada variable crearemos un par de métodos para leer y modificar esa
variable de instancia. A este par de métodos se les llama colectivamente accessors (accededores).

En el capítulo 8 descubrimos el método setIntValue: de la clase NSTextField . Este método hace pareja con el método
intValue ( setIntValue asigna el valor e intValue lee el valor). Juntos forman dos de los métodos accessor de
NSTextField .

Accessors
¿Qué aspecto tiene esto en el código? Veamos el siguiente ejemplo.
//[2]
@interface MiPerro : NSObject {
NSString * _nombre; //[2.2]
}
- (NSString *)nombre;
- (void)setNombre:(NSString *)valor;
@end

Esta interfaz de la clase MiPerro tiene una variable de instancia, una cadena de texto llamada _nombre [2.2]. Para poder leer y
cambiar el nombre del perro (almacenado en la variable de instancia _nombre), hemos definido dos métodos: nombre y
setNombre: .

La implementación sería algo así:


//[3]
@implementation MiPerro
- (NSString *)nombre {
return _nombre; //[3.3]
}
- (void)setNombre:(NSString *)valor {
_nombre = valor; //[3.6]
}
@end

En el primer método [3.3] devolvemos simplemente la variable de instancia. En el segundo método [3.6] asignamos a la variable
de instancia el valor pasado como argumento. Hemos simplificado la implementación por claridad, lo habitual es añadir código
para gestión de memoria dentro de estos métodos. En el ejemplo 4 vemos un ejemplo más real:

//[4]
@implementation MiPerro
- (NSString *)nombre {
return [[_nombre retain] autorelease];
}
- (void)setNombre:(NSString *) valor {
if (_nombre != valor) {
[_nombre release];
_nombre = [valor copy];
}
}
@end

No vamos a entrar en detalle sobre este código (ver el capítulo 15), pero podríamos decir que el código en [4] es equivalente a
[3], más instrucciones para copiar, retener y liberar memoria. Las instrucciones de gestión de memoria varían según el tipo de
dato. No se recomienda usar el guión delante del nombre de las variables, lo hemos puesto por claridad en nuestro ejemplo con
la variable de instancia _nombre , pero podríamos haberlo llamado igual que el método ( nombre ) y no habría conflicto ya que
variables y métodos usan espacios de nombres diferentes.

Propiedades
Con Leopard y Objective-C 2.0 aparecen nuevas características que permiten economizar cuando usamos patrones de código
habituales. La nueva característica de la que estamos hablando se llama propiedades. Con ella el ahorro de código es

http://www.cocoalab.com/?q=book/export/html/60 Página 56 de 59
BecomeAnXcoder-Español 19/05/10 20:25

significativo y ello implica por supuesto menos código que depurar en caso de errores.

¿En qué se diferencian las propiedades de los accessors? En esencia, las propiedades sintetizan directamente los accessors,
usando la más apropiada y eficiente gestión de memoria. En otras palabras, escriben los métodos accessor por ti, aunque el
código de estos métodos no queda a la vista.

El ejemplo [2] usando propiedades quedaría así:

//[5]
@interface MiPerro : NSObject {
NSString * nombre;
}
@property (copy) NSString *nombre;
@end

Y la implementación quedaría así:

//[6]
@implementation MiPerro
@synthesize nombre;
@end

Puedes comprobar que el código se ha simplificado realmente. Si resulta que tu clase tiene muchas variables que necesitan
accessor, imagínate lo que te facilita la vida el uso de propiedades.

15: Gestión de memoria


Presentación
Es el momento de explicar las sentencias que habían quedado pendientes hace ya varios capítulos. Esas instrucciones trabajan
con la memoria. Tu programa no es el único que va estar ejecutándose en tu Mac y la memoria es un bien valioso. Por tanto
cuando tu programa no necesite la memoria que ha requerido debe devolverla al sistema. Así que cuando tu madre te decía que
debías ser educado y vivir en armonía con la comunidad ¡te estaba enseñando a programar!. Incluso si tu programa fuese el
único ejecutándose, la memoria no liberada iría arrinconando a tu programa haciéndolo ir a paso de tortuga.

Recolección de basura
Las técnicas de gestión de memoria que usa Cocoa y que se explican más adelante en este capítulo se llaman recuento de
referencias (Reference Counting). Encontrarás explicaciones más completas en libros o artículos más avanzados (ver capítulo
15).

Mac OS X 10.5 Leopard presenta un nuevo sistema de gestión de memoria para Objective-C 2.0, llamado Recolección de
basura de Cocoa (Garbage Collection). La recolección de basura gestiona la memoria automáticamente, eliminando la necesidad
de retener, liberar o autoliberar los objetos explícitamente.

La magia de la recolección de basura trabaja con todos los objetos de Cocoa que heredan de NSObject o NSProxy y permite al
programador escribir menos código que en versiones anteriores de Objective-C. En la práctica no hay mucho más que decir,
puedes olvidar todo lo que has aprendido en este capítulo.

Activar la recolección de basura


Es necesario activar la recolección de basura, ya que por defecto está apagada en cada proyecto nuevo de Xcode. Para ello
selecciona el nombre de tu proyecto en el panel Groups & Files y pulsa el botón Info. En el panel de botones superior
selecciona Build y en el filtro de búsqueda de ajustes (Search in build settings) empieza a escribir garbage collection. Verás
aparecer el ajuste con el valor Unsupported. Puedes seleccionar "Supported" o "Required". La primera opción permite que en tu
programa coexistan el sistema clásico de retener/liberar memoria junto a la recolección de basura automática. La segunda
opción obliga a que todos los módulos de tu programa usen únicamente la recolección de basura automática.

Recuento de referencias: el ciclo de vida del objeto


Si te interesan las técnicas de gestión de memoria anteriores a Leopard, sigue leyendo.

Cuando tu programa crea un objeto, el objeto ocupa un espacio en memoria y debes liberar ese espacio cuando el objeto ya no se

http://www.cocoalab.com/?q=book/export/html/60 Página 57 de 59
BecomeAnXcoder-Español 19/05/10 20:25

use más, es decir, deberías destruir el objeto. El problema es que no siempre es fácil determinar cuando el objeto deja de ser
usado.

Por ejemplo, durante la ejecución del programa, tu objeto puede ser referenciado por muchos otros objetos y no debería por
tanto destruirse mientras haya la posibilidad de que cualquiera de esos objetos lo vayan a usar (intentar usar un objeto que ha
sido destruido puede hacer que tu programa rompa o se comporte de forma impredecible).

La cuenta de retención
Para ayudar a destruir objetos que ya no son necesarios, Cocoa asigna un contador a cada objeto, que representa su "cuenta de
retención". Así que en tu programa, cuando referencias un objeto, deberías incrementar la cuenta de retención en 1. Y cuando
eliminas la referencia a un objeto, deberías decrementar la cuenta de retención. Cuando la cuenta de retención de un objeto es
igual a 0, el objeto sabe que nadie lo referencia y por tanto se autodestruye con seguridad, liberando la memoria asociada.

Por ejemplo, supongamos que tu aplicación es un reproductor de música y que tiene objetos que representan canciones y listas
de reproducción. Supongamos que una canción está en tres listas de reproducción. Si no está referida en ningún otro sitio,
entonces el valor de la cuenta de retención de la canción es igual a 3.

Un objeto conoce cuantas veces está referenciado por otros objetos gracias a su cuenta de retención

Retain y Release
Para incrementar la cuenta de retención de un objeto, lo que debemos es enviarle el mensaje retain .

[miObjeto retain];

Para decrementar la cuenta de retención de un objeto, le enviamos el mensaje release .


[miObjeto release];

Autorelease
Cocoa también ofrece un mecanismo llamado "pool de autorelease", que permite enviar un mensaje de liberación retardada a un
objeto. Para usarlo, debes registrar el objeto en lo que se llama "pool de autorelease", enviándole un mensaje autorelease .
[miObjeto autorelease];

El pool de autorelease se ocupará de enviar el mensaje de liberación a tu objeto cuando sea conveniente. Las sentencias que
tratan con los pool de autorelease que pudimos ver en capítulos anteriores se ocupan de ajustar correctamente toda esta
maquinaria de autoliberación de objetos.

16: Fuentes de información


El modesto objetivo de este libro era enseñarte los principios de Objective-C en el entorno Xcode. Si has repasado su contenido
al menos un par de veces y has probado los ejemplos realizando tus propias variaciones, entonces estás preparado para escribir

http://www.cocoalab.com/?q=book/export/html/60 Página 58 de 59
BecomeAnXcoder-Español 19/05/10 20:25

las aplicaciones que desees crear. Este libro te ha dado suficiente conocimiento para meterte pronto en problemas. Estás listo
para explotar otros recursos y podrías empezar por los que se listan a continuación. Un aviso importante antes de que empieces
a escribir tu código: ¡no empieces inmediatamente! Echa un vistazo a los marcos de trabajo, ya que Apple puede haber hecho ya
el trabajo por ti, o al menos suministrar clases que requieran poco esfuerzo por tu parte para satisfacer tus necesidades.
También puede que otros hayan trabajado en lo que necesites y tengan el código fuente disponible. Así que ahorra tu propio
tiempo consultando la documentación y buscando en internet. El primer sitio debería ser la web de desarrollo de Apple en
http://developer.apple.com

Te recomendamos también que añadas a tus marcadores:

http://osx.hyperjeff.net/reference/CocoaArticles.php
http://www.cocoadev.com
http://www.cocoadevcentral.com
http://www.cocoabuilder.com
http://www.stepwise.com

Estos sitios enlazan a otros muchos lugares y fuentes de información. También podrías suscribirte a la lista de correo de
desarrollo Cocoa en http://lists.apple.com/mailman/listinfo/cocoa-dev. Este es un lugar en el que puedes plantear tus preguntas y
sus miembros harán todo lo posible por ayudarte. Antes de formular tu pregunta lee los archivos por si otros ya la han hecho
antes en http://www.cocoabuilder.com. Sigue estos consejos para hacer preguntas de forma inteligente:
http://www.sindominio.net/ayuda/preguntas-inteligentes.html

En español puedes encontrar tutoriales interesantes en http://macprogramadores.org. Para complementar este documento puedes
leer:

El lenguaje Objective-C para programadores C++ y Java


Programación Cocoa con Foundation Framework

Hay varios libros buenos sobre desarrollo con Cocoa. Programming in Objective-C está orientado para principiantes. Algunos
libros asumen que tienes al menos el conocimiento que puedes obtener de este libro. Hemos disfrutado con Cocoa Programming
for Mac OS X de Aaron Hillegass of the Big Nerd Ranch y también Cocoa with Objective-C de James Duncan Davidson y
Apple, publicado por O'Reilly.

Finalmente unos consejos sobre precaución. Estás programando para el Mac. Antes de liberar tu programa, asegúrate no sólo de
que no tiene errores sino también de que tiene buen aspecto y se ajusta a las guías de interfaz humana de Apple (que están
descritas en este vínculo). Una vez que lo hayas hecho, no seas tímido y haz tu programa disponible para todos. Los
comentarios que te puedan hacer los demás te ayudarán a refinar y ampliar tu aplicación y seguir manteniendo tu atención en la
calidad.

Esperamos que hayas disfrutado este libro y continúes programando con Xcode.

Bert, Alex, Philippe.

Licencia

Este trabajo está bajo licencia


Creative Commons Attribution 3.0.

Versión
Version 1.15

19 February 2008

http://www.cocoalab.com/?q=book/export/html/60 Página 59 de 59

También podría gustarte