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]
NSString *ordenadorFavorito;  // [2.1]
ordenadorFavorito = @"¡Mac!";
NSLog(ordenadorFavorito);

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

 //[3]
int *y;

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

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

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

El símbolo @

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

Un nuevo tipo de cadena

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

Ejercicio

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

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

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

Una vez que se le ha dado un valor a la cadena, se le podría asignar otro valor, pero no se puede modificar la propia cadena [5.7], porque es una instancia de la clase NSString. Enseguida aclaramos esto.

//[5]
#import <foundation/foundation.h>
int main (int argc, const char *argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSString *ordenadorFavorito;
    ordenadorFavorito = @"iBook";  // [5.7]
    ordenadorFavorito = @"MacBook Pro";
    NSLog(@"%@", ordenadorFavorito);
    [pool release];
    return 0;
}

Cuando se ejecuta, el programa imprime:

MacBook Pro

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

NSMutableString

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

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

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

Ejercicio

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

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

Cuando se ejecuta, este programa muestra:

La longitud es 7.

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

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


- (unsigned int)length

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


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

//[7]
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *foo, *bar;
    foo = @"¡Julia!";
    bar  = [foo uppercaseString];
    NSLog(@"%@ se converte a %@.", foo, bar);
    [pool release];
    return 0;
}

Si lo ejecutas, mostrará:

¡Julia! se converte a ¡JULIA!

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

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

Cuando se ejecute, el programa mostrará:

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

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

De nuevo más punteros

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

25 Pointers 1

Los objetos siempre se usan mediante punteros

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

bar = foo;

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

26 Pointers 2

Múltiples variables pueden referenciar el mismo objeto

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

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

Cuando se ejecuta el programa, muestra:

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

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

Post new comment

The content of this field is kept private and will not be shown publicly.
Enter the code shown in the image:

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
1 + 10 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.

Donate!





If you like what you find here and wish to support further development of this site, please donate via PayPal. No account required.

Syndicate

Syndicate content

User login

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
12 + 2 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
Enter the code shown in the image: