You are on page 1of 92

Conviertete en Xcoder

Comienza a programar en Mac usando Objetive-C

Conviertete en Xcoder Comienza a programar en Mac usando Objetive-C Por Bert Altenberg, Alex Clarke y

Por Bert Altenberg, Alex Clarke y Philippe Moughin

Licencia

Copyright © 2006 por Bert Altenburg, Alex Clarke and Philippe Mougin. Version 1.14. Liberado bajo la Licencia Creative Commons License: 2.5 Attribution Non-commercial

http://creativecommons.org/licenses/by/2.5/

Atribución: Los licenciantes, Bert Altenburg, Alex Clarke and Philippe Mougin, permiten copiar, modificar y distribuir el trabajo. A cambio, los licenciatarios deben otorgar el crédito a los autores originales. No-comercial: Los licenciantes permiten la copia, modificación y distribución del trabajo y usarlo en cursos remunerados o gratuitos. A cambio, los licenciatarios no pueden vender la obra en sí, pero ésta puede acompañar a otro trabajo que se venda.

Contenido

Introducción 00: Antes de empezar 01: Un programa es una serie de instrucciones 02: ¿ Sin comentarios ? ¡ Inaceptable ! 03: Funciones 04: Salida en pantalla 05: Compilación y ejecución de un Programa 06: Sentencias condicionales 07: Ejecución de bucles 08: Programas con entorno gráfico 09: Búsqueda de métodos 10: awakeFromNib 11: Punteros 12: Cadenas de caracteres 13: Arrays 14: Accesorios y Propiedades 15: Gestión de memoria 16: Fuentes de información

Become an Xcoder – Español – v1.15

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

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.

Become an Xcoder – Español – v1.15

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.

Become an Xcoder – Español – v1.15

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!

Become an Xcoder – Español – v1.15

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

Become an Xcoder – Español – v1.15

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 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.

Become an Xcoder – Español – v1.15

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;

Become an Xcoder – Español – v1.15

areaDibujo = anchoDibujo

*

altoDibujo;

Enteros y fraccionarios

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,

Become an Xcoder – Español – v1.15

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:

Nombre

void

int

unsigned

float

double

char

Tipo

Ejemplo

Vacío

Nada

Número entero

-1,

0, 1, 2

Número entero positivo

Número fraccionario

Número fraccionario de doble precisión

Carácter

0, 1, 2

-0.333, 0.5, 1.223, 202.85556

0.52525252333234093890324592793021

hola

Become an Xcoder – Español – v1.15

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.

+

- / división * multiplicación

suma

resta

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;

Become an Xcoder – Español – v1.15

x++;

y

// 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++

// [13.2]

* x;

= 2

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í.

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)

Become an Xcoder – Español – v1.15

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:

//[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 …"

Become an Xcoder – Español – v1.15

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

Become an Xcoder – Español – v1.15

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 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.

Become an Xcoder – Español – v1.15

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]

Become an Xcoder – Español – v1.15

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]

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]).

Become an Xcoder – Español – v1.15

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;

[5.4]

return area;

}

// pi veces el cuadrado del radio

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;

}

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.

Become an Xcoder – Español – v1.15

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]

//

Become an Xcoder – Español – v1.15

float calculaAreaDelCirculo(float radio)

{

float area; // [10.14] area = 3.1416 * radio * radio; return area;

}

// [10.12]

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 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

Become an Xcoder – Español – v1.15

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].

Become an Xcoder – Español – v1.15

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 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()

Become an Xcoder – Español – v1.15

//[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");

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);

Become an Xcoder – Español – v1.15

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);

Become an Xcoder – Español – v1.15

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; 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);

Become an Xcoder – Español – v1.15

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;

}

Become an Xcoder – Español – v1.15

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

Introducción

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 El asistente de Xcode te pe rmite crear nuevos

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Introduce un nombre para tu aplicación, como "justatry". Selecciona

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().

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Xcode mostrando la función main(). //[1] #import

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].

Become an Xcoder – Español – v1.15

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.

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.

ld and Run" para que se compile y ejecute el programa. El botón Build and Run.

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.

Become an Xcoder – Español – v1.15

//[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") coma! [pool drain]; //[2.9] return 0;

}

//¡Oh, he olvidado el punto y

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].

Aparecerá un indicador rojo antes de la línea [2.9]. Xcode señala un error de compilación. Según

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 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

Become an Xcoder – Español – v1.15

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

Become an Xcoder – Español – v1.15

los valores de las variables. En ese punto Xcode insertará un "breakpoint" (punto de ruptura), representado por una flecha azul.

(punto de ruptura), representado por una flecha azul. Colocando breakpoints (puntos de ruptura) en nuestro

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ú.

en el icono del martillo hasta que aparezca un menú. El botón de compilar y depurar.

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…

Become an Xcoder – Español – v1.15

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:

La ventana del Debugger tendrá un aspecto parecido a este: 05: Compilación y ejecución de un

Become an Xcoder – Español – v1.15

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!

Become an Xcoder – Español – v1.15

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"

{

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

Become an Xcoder – Español – v1.15

>

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); valor 0.

// después de esta instrucción, la variable 'y' tendrá el

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]

// 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.");

}

Become an Xcoder – Español – v1.15

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.");

}

}

Become an Xcoder – Español – v1.15

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

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

Become an Xcoder – Español – v1.15

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;

Become an Xcoder – Español – v1.15

}

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);

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).

Become an Xcoder – Español – v1.15

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Se envía un mensaje de cierre a la ventana

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.

Safari y un sitio web no tiene una representación visual. Un objeto (por ej. la ventan

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

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.

Become an Xcoder – Español – v1.15

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Un esquema de la aplicación que queremos crear Cuando

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.

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Un esquema del intercambio de mensajes entre objetos de

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Haz doble-click en el fich ero MainMenu.xib de Xcode

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Arrastrando objetos de la ventana "Libra ry" hasta la

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.

Become an Xcoder – Español – v1.15

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!

de tu aplicación sin escribir una sola línea de código! Nuestra ventana en Interface Builder, junto

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 La clase Application Delegate que se incluye con cada

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.

Become an Xcoder – Español – v1.15

¿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.

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Creación de la clase MPAClaseEjemplo Después de pulsar Finish

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.

Become an Xcoder – Español – v1.15

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 desplegable superior y selecciona Objects & Controllers. Después arrastra un Object (tiene el icono de un cubo azul) hasta la clase MainMenu.xib.

ne el icono de un cubo azul) hasta la clase MainMenu.xib. Instanciando un nuevo objeto 08:
ne el icono de un cubo azul) hasta la clase MainMenu.xib. Instanciando un nuevo objeto 08:
ne el icono de un cubo azul) hasta la clase MainMenu.xib. Instanciando un nuevo objeto 08:

Instanciando un nuevo objeto

Become an Xcoder – Español – v1.15

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.

la comunicación entre nuestro código y la interfaz. Asignando la identidad a nuestro objeto Creación de

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

Become an Xcoder – Español – v1.15

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".

activa la opción "View icons and descriptions". La clase MPAClaseEjemplo en la librería de clases 08:

La clase MPAClaseEjemplo en la librería de clases

Become an Xcoder – Español – v1.15

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.

en dos puntos (":"). Lo explicaremos después. Creación de métodos en nuestra clase MPAClaseEjemplo

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".

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Creación de un outlet en la clase MPAClaseEjemplo Antes

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

Become an Xcoder – Español – v1.15

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:".

la clase. Ahí seleccionaremos "asignarValor5:". Estableciendo la conexión Ahora el botón mantiene una

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Si vas ahora a Xcode, en la ventana de

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Vemos en nuestro proyecto Xcode los ficheros generados Retrocedamos

Vemos en nuestro proyecto Xcode los ficheros generados

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.

Become an Xcoder – Español – v1.15

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

Become an Xcoder – Español – v1.15

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.

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.

la ventana de tu aplicac ión y podrás probarla. Nuestra aplicación funcionando Hemos creado con unos

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

Become an Xcoder – Español – v1.15

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.

Become an Xcoder – Español – v1.15

Become an Xcoder – Español – v1.15 Navegando por la documentación de Xcode. En lo primero

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)

Become an Xcoder – Español – v1.15

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.

- (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.

Become an Xcoder – Español – v1.15

¿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.

Become an Xcoder – Español – v1.15

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 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

Companion document Resource Programming Guide

Declared in

/System/Library/Frameworks/AppKit.framework

NSNibLoading.h

Become an Xcoder – Español – v1.15

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

-

(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.

Become an Xcoder – Español – v1.15

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

Become an Xcoder – Español – v1.15

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:

//[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

Become an Xcoder – Español – v1.15

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

Become an Xcoder – Español – v1.15

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]

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]