Curso Básico de Objective C: Objetos NS:NSDate, NSArray, NSDictionary y NSString

NSDate

Es uno de los objetos principales de la biblioteca Fundation, nos permite manejar fechas y traducirlas a Cadenas y viceversa. 
        NSDate *fecha   =[[NSDate alloc]init];
        NSLog(@”%@”, fecha );
Como podemos ver en el ejemplo una fecha puede ser inicializada como un objeto normal. Al intentar imprimirla por consola, nos saca un mensaje similar al siguiente:

2014-03-13 00:48:10.323 03_objetos_principales[1467:303] 2014-03-12 23:48:10 +0000

Donde la parte importante es:
2014-03-12 23:48:10 +0000

Que es la fecha inicial del momento en el que se ejecutó la sentencia. Como puede verse nos devuelve un formato cadena en el indica en el siguiente orden:

  • año
  • mes
  • dia
  • hora
  • minuto
  • segundo
  • franja horaria

Este es el formato anglosajón de fechas, aunque podríamos llegar a obtener la información en segundos desde el 1 de enero de 1970, de la siguiente manera:

        double segundosdesde1970=[fecha timeIntervalSince1970];
        NSLog(@”%f”,segundosdesde1970);

Aunque lo que normalmente nos suele interesar en disponer de una fecha un poco más legible por parte del usuario:

NSLog(@”Descripcion:%@”,[fecha descriptionWithLocale:[NSLocale currentLocale]]);

Lo cual nos saldrá una salida en nuestro idioma por defecto:

jueves, 13 de marzo de 2014 00:56:09 Hora estándar de Europa central

También suele ser interesante la generación de una fecha en base a una fecha que a nosotros nos interese:

NSDate *fecha2=[[NSDate alloc] initWithString:@”2001-03-24 10:45:32 +0600″];

Con este tipo de inicialización indicamos los datos de la fecha con el mismo orden que indicamos anteriormente y tendremos un objeto NSDate con la fecha indicada.

Y luego podríamos gestionar un salida por pantalla eligiendo los datos y el orden de los mismos gestionando el formato de la cadena de salida:

NSLog(@”%@”,[fecha2 descriptionWithCalendarFormat:@”%d/%m/%Y” timeZone:nil locale:[NSUserDefaults standardUserDefaults]]);

Esto nos proporciona una salida similar a la siguiente:

24/03/2001

NSArray

Los arrays son una necesidad a la hora de gestionar conjuntos de datos, para ello Objective C nos provee de esta clase que nos facilita las cosas a la hora de gestionar los arrays.

Veamos un ejemplo de inicialización de un array con dos elementos:

 NSArray * array= [NSArray arrayWithObjects:@”uno”@”dos”nil];

Como se puede ver tenemos un array con dos elementos, el primero es un cadena de caracteres con el valor uno y el segundo otra cadena. Para inicializar el array utilizamos un método de clase llamado arrayWithObjects que nos permite un número indefinido de parámetros. De lo único que debemos recordar es que debemos terminar con un último parámetro cuyo valor sea nil para terminar la definición de los elementos. Y nos devolverá el array con los objetos que le hemos indicado.

Es una manera muy fácil de rellenar estos arrays, veamos ahora las funciones típicas de uso de arrays, empezando por el atributo count:

NSLog(@”%lu”, (unsigned long)array.count);

Con count podemos ver el número de elementos que tiene el array.

Con el objectAtIndex podemos pedirle que nos devuelva el objeto que esté presente en una posición:

NSLog(@”%@”, [array objectAtIndex:0]);

for-each

Este tipo especial de bucle está preparado para recorrer colecciones de elementos, de una manera similar a cómo sucede en Java, veamos un ejemplo:
        for (id object in array) {
            NSLog(@”%@”, object);
        }
Como puede verse tenemos un array y lo vamos a recorrer con el bucle. En cada una de las iteraciones tendremos un objeto llamado object que tendrá el valor del objeto que se encuentre en la posición que corresponda dentro de la iteración. Empezando por el primer objeto y terminando por el último. Así recorreremos el array de una manera muy cómoda.

Otras métodos interesantes

También disponemos de un método que nos permite si un objeto está presente dentro del array llamado containsObject :
       NSLog(@”%d”,[array containsObject:@”uno”]);
Como puede verle le pasamos como parámetro el objeto que estamos buscando. Nos devolverá un valor entero 1 si está 0 si no está. 
El método indexOfObject nos permite buscar un elemento en el array y nos devuelve la posición del objeto:
NSLog(@”%lu”,(unsigned long)[array indexOfObject:@”uno”]);
 Y ya por último el método   nos permite saber si dos arrays son iguales o no:
NSLog(@”%hhd”,[array isEqual:array]);

NSMutableArray

Con esta clase podremos manejar un array de objetos pero en el que podremos modificar dinámicamente en tiempo de ejecución el número de objetos que contiene. Veamos su inicialización:
NSMutableArray *arraymutable=[[NSMutableArray alloc]init];
Como vemos se inicializa como un objeto normal.
Para añadir objetos usaremos el método addObject  como en el ejemplo:
[arraymutable addObject:@”uno”];
También disponemos de un método que permite eliminar un objeto según su posición:
[arraymutable removeObjectAtIndex:0];
Evidentemente los NSMutableArray también pueden ser recorridos con un for-each, coger un elemento por su posición y contar el número de elementos:
        
        for (id object in arraymutable) {
            NSLog(@”%@”, object);
        }

        NSLog(@”%lu”, (unsigned long)[arraymutable count]);
        
        NSLog(@”%@”, [arraymutable objectAtIndex:0]);
       
        NSLog(@”%@”,arraymutable);

NSDictionary

Los NSDictionary nos van a permitir guardar pares de objetos en forma de listado.  Cada par dispone de una clave y un valor.  Veamos cómo inicializar un diccionario:

        NSDictionary *diccionario=[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@”uno”@”dos”nilforKeys:[NSArray arrayWithObjects:@”1″,@”2″nil]];

Como pude verse se utiliza el método dictionaryWithObjects la cual necesita dos parámetros un array con los valores y otro con las claves. En el ejemplo estamos inicializando dos arrays en la misma línea de inicialización del diccionario.

Para recoger el valor relacionado con una clave, usaremos el método objectForKey para lo cual necesitamos pasarle como parámetro la clave relacionada:

NSLog(@”%@”, [diccionario objectForKey:@”1″]);

Para recorrer el diccionario podemos usar un foreach, de la siguiente manera:

        for (NSObject* key in diccionario) {
            id value = [diccionario objectForKey:key];
            NSLog(@”Clave:%@”, key);
            NSLog(@”Valor:%@”, value);
        }

  También podemos recoger todos las claves y los valores con estos dos métodos:

        NSLog(@”%@”,[diccionario allKeys]);
        NSLog(@”%@”,[diccionario allValues]);       

NSMutableDictionary

Los NSMutableDictionary funcionan de una manera similar a los NSDictionary pero pudiendo modificar al vuelo los objetos que almacena. Veamos un ejemplo de inicialización:

        NSMutableDictionary *diccionariomutable=[[NSMutableDictionary alloc]init];

En este caso, lo estamos inicializando de manera vacía. Ahora intentaremos añadir un nuevo par al diccionario:
        [diccionariomutable setValue:@”uno” forKey:@”1″];

En este caso estamos añadiendo una cadena de caracteres como primer parámetro, el valor, y como segundo parámetro la clave relacionada. 

Por supuesto podemos coger el valor asociado a una clave:
        NSLog(@”%@”, [diccionariomutable objectForKey:@”1″]);
También podemos borrar todos los elementos del diccionario:
        [diccionariomutable removeAllObjects];
Borrar elementos por su clave:
        [diccionariomutable removeObjectForKey:@”1″];
Recorrer el diccionario:
        for (NSObject* key in diccionariomutable) {
            id value = [diccionariomutable objectForKey:key];
            NSLog(@”%@”, value);
        }

NSString

 La Clase NSString permite el almacenamiento de una cadena de caracteres. Veamos un ejemplo de  inicialización básico:

        NSString *cadena=[[NSString alloc]init];
        cadena=@”Literal”;

Con la propiedad length podemos saber la longitud de la cadena:

       NSLog(@”logitud: %lu”,(unsigned long)cadena.length);

 Ahora veremos una inicialización directa con un literal:

        NSString *otracadena=[[NSString allocinitWithString:@”Otro Literal”];

Podemos inicializarla también mediante un formato con variables:
        NSString *cad=[[NSString allocinitWithFormat:@”con formato %@”,cadena, nil];
Incluso recorrerla con un for:
        for (int i=0; i<cad.length; i++) {
            NSLog(@”%c”,[cad characterAtIndex:i]);
        }
Convertirla en mayúsculas:
        NSLog(@”%@”,[cad uppercaseString]);
minúsculas:
        NSLog(@”%@”,[cad lowercaseString]);
saber si es igual a otra cadena:
        NSLog(@”%d”,[cad isEqual:cad]);
saber si tiene un prefijo o un sufijo:
        NSLog(@”%d”,[cad hasPrefix:@”con”]);
        NSLog(@”%d”,[cad hasSuffix:@”Literal”]);

NSMutableString

Este tipo especial de cadena de caracteres es modificable sin la necesidad de crear nuevos objetos constantemente, veamos su inicialización:
NSMutableString *mutante=[[NSMutableString alloc]initWithFormat:@”Cadena con numero %d”3];
Podemos añadir contenido al final de la cadena:
        [mutante appendString:@” con apendice”];
Incluso hacer copias de cadenas:
        NSMutableString *nuevacadena=[cad mutableCopy];

NSNumber

Nos permite almacenar números enteros, aquí hay un ejemplo de inicialización y uso:
        NSNumber *numero=[[NSNumber alloc]initWithInt:7];
        NSLog(@”%d”,numero.intValue);
        NSLog(@”%@”,numero);

EJERCICIOS PROPUESTOS

  • Crea un nuevo proyecto que permita realizar estos ejercicios.
  • Crea una nueva clase que se llama Evento, que contenga los siguientes datos: identificativo numérico, nombre, lugar, fecha inicio, fecha fin, número de asistentes.
  • Crea un constructor sin parámetros y otro con parámetros en la clase Evento.
  • Dentro del main.m: crea un par de objetos de la Clase Evento. El primero inicializarlo con el constructor sin parámetros y el segundo con el constructor con parámetros.
  • Meter los datos en las propiedades del primer objeto mediante el uso de sus propiedades.
  • Modificar los datos del segundo objeto mediante los setter.
  • Crea un array estático de 3 objetos de tipo Evento.
  • Imprime por consola el segundo elemento del array.
  • Crea un array dinámico de 20 objetos de tipo Evento. 
  • Imprime por consola todos los datos de cada Evento del array dinámico. 
  • Eliminar el último objeto del array dinámico y vuelve a presentarlo por consola. 
  • Cre un diccionario dinámico que contenga los datos de un Evento como valores dentro del diccionario, las claves relacionadas con esos valores serán cadenas de caracteres con el nombre de la propiedad del objeto Evento. Es decir, en la clave @”nombre” deberá estar el nombre del evento, y el resto igual. 

Curso Básico de Objective C: Protocolos y Delegados

Protocolos (protocols)

Una de las cuestiones principales en cualquier lenguaje de programación es la menea en la cual se definen los conjuntos de funcionalidades, el cómo tienen que funcionar algo, para que luego alguien pueda realizar una implementación con éxito.

Los protocolos en Objective C son algo similar a los interfaces en Java. Permiten definir un conjunto de propiedades y métodos para que luego puedan ser implementados por parte de otras clases.

Creación de un protocolo

Para crear  un nuevo protocolo se realiza de una manera similar a la de la creación de una clase, utilizando el menús File->New->New File o pulsando Comando+N en Xcode. Nos aparecerá la siguiente pantalla de selección:

Bien estemos creando un programa para iOS o para Mac OSX seleccionaremos Cocoa Touch o Cocoa y en la parte derecha seleccionaremos Objective C protocol y pulsamos en Next. Nos aparecerá la siguiente pantalla:

Aquí podremos configurar el nombre del protocolo, recuerda seguir la misma nomenclatura que con las clases, CamelCase con prefijo. Pondremos por ejemplo MiProtocolo y pulsamos en Next.

Ahora veremos la pantalla de selección de guardado:

Indicamos donde queremos guardar el fichero y pulsamos el botón Create. Y nos debería aparecerá el siguiente código:

//
//  MiProtocolo.h
//  01_clases
//
//  Created by pepesan on 12/03/14.
//  Copyright (c) 2014 pepesan. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol MiProtocolo <NSObject>

@end

Como podemos ver en el código, a parte de los comentarios y el import de las clases fundacionales, nos encontramos con que el código del protocolo se verá incluido entre el @protocol y el @end . A continuación escribimos el nombre del protocolo y luego decimos que debería implementar este protocolo. En este caso sería una especie de herencia de propiedades y atributos de otro protocolo el NSObject por eso se coloca después del nombre del protocolo y entre <>. Como puede verse en el código de Objective C antes de definir una clase NSObject se define un protocolo de como debe funcionar un NSObject.

Con el código de ejemplo decimos que todo protocolo debe funcionar como un NSObject de base y luego contendrá todo aquello que queramos añadir.

Para poder añadir propiedades y métodos lo podemos hacer exactamente igual a como lo hacíamos en una clase, lo único es que no tenemos porque definir la implementación, sino solo las definiciones, por lo que para definir un protocolo sólo necesitamos crear un fichero .h de cabecera.

Inclusión de propiedades y métodos

A continuación  un ejemplo de inclusión de una propiedad y un método:

#import <Foundation/Foundation.h>
@protocol MiProtocolo <NSObject>
@property int i;
– (void) hazAlgo;

@end

Implementación de un Protocolo

Un protocolo por si mismo no tiene sentido si no realizamos implementaciones de dicho protocolo y para ello lo realizamos mediante una nueva clase que llamaremos Implementadora. Creamos la clase de la manera habitual, le indicamos que su padre es la clase NSObject, veamoslo en código del fichero de cabecera:
#import <Foundation/Foundation.h>
@interface Implementadora : NSObject 
@end

A continuación debemos incluir la dependencia del protocolo MiProtocolo, empezamos por añadir el import del protocolo:

#import “MiProtocolo.h”

Y a continuación después del nombre de la clase padre, indicamos entre <> el nombre del protocolo que queremos implementar en la clase:

@interface Implementadora : NSObject <MiProtocolo

De esta manera sería como hacerlo similar al implements NombreDeInterfaz en Java.

Ahora es cuando tendríamos que codificar la implementación del protocolo en la clase, dentro del fichero .m:

#import “Implementadora.h”
@implementation Implementadora
@synthesize i;
– (void) hazAlgo{
    NSLog(@”estoy haciendo algo!”);
}

@end

Como podemos ver sintetizamos la propiedad i definida en el protocolo y realizamos la implementación del método definido en el protocolo.

Así que se puede decir que la clase Implentadora implementa el protocolo MiProtocolo con todos sus propiedades y métodos.

Si necesitara implementar varios protocolos en una misma clase sólo tendría que separarlos con comas dentro de los <>, por ejemplo:

@interface Implementadora : NSObject <MiProtocolo, MiOtroProtocolo

Métodos opcionales y requeridos

Una de las características específicas de los protocolos es que nos permiten indicar que métodos son los requeridos mínimos de la implementación y cuales de ellos son opcionales. Por lo que en el caso de que debamos realizar una implementación de un protocolo siempre deberemos implementar los requeridos dejando a nuestro criterio ver si realmente necesitamos o no implementar los métodos opcionales. 
Veamos un ejemplo de protocolo con métodos requeridos y opcionales:
#import <Foundation/Foundation.h>
@protocol MiProtocolo <NSObject>
@property int i;
@required;
– (void) hazAlgo;
@optional;
-(void) hazOtraCosa;
@end

Como podemos ver disponemos de dos nuevas a notaciones  @required y @optional de esta manera colocándolas delante de cada método podemos indicar si es requerido u opcional respectivamente.

Si dejamos el código de la función implementadora tal como está no debería haber ningún problema, porque hemos implementado el método requerido, y aunque no hemos implementado el segundo método, como está definido como opcional, no tenemos la obligación de implementarlo y nuestro programa compilará sin problemas.

Aunque la comprobación de los métodos opcionales en Objective C se realiza en tiempo de ejecución, el programa fallará si se intenta ejecutar un método opcional no implementado.

Delegados (delegate)

Uno de los usos principales de los protocolos es la implementación de delegados. Los delegados en Cocoa y Cocoa Touch (MacOSX e iOS respectivamente), las bibliotecas gráficas, son los responsables de definir cómo tienen que funcionar las vistas de una aplicación. Por ejemplo el UITableView de iOS suele requerir de la implementación no de uno, sino de dos protocolos, como son el UITableViewDelegate y el UITableViewDataSource .
De esta manera cualquier escena definida en un proyecto iOS requerirá que se implementen un conjunto de métodos en la clase UIViewController que controle una escena.  Las UIViewController son lo más parecido a las Activity de Android. 
Por lo tanto podremos decir que la clase que implemente los protocolos sería una candidata a ser delegada de dichos métodos. Vamos que podría ser capaz de manejar esas vistas. 

Referencias

Curso básico de Objective C: Clases y Objetos

Primeros Pasos

Como buen lenguaje de programación orientado a objetos Objective C permite el uso de clases en el código. A continuación veremos varios ejemplos de uso de las Clases.

Empecemos por dar de alta una clase en Xcode en un proyecto cualquiera. Para ello deberemos pulsar  Comando + N para un crear un nuevo fichero, a continuación aparecerá el siguiente diálogo:

En la parte izquierda podemos ver los distintos tipos de ficheros que podemos crear. Seleccionaremos Cocoa o Cocoa touch dependiendo de si estamos haciendo una aplicación para Mac OSX o para iOS y pulsamos en Next, a continuación nos preguntará por el nombre de la clase y su herencia:

Pondremos el nombre de la clase en el campo Class e indicaremos en el selector, o escribiremos el nombre directamente, de la Clase Padre de la nueva clase que vamos a crear.
NSObject es la Clase principal del Objective C, aquellos que vengan de Java verás que es muy similar en concepto y métodos a los que nos encontramos en la clase Object.
Por lo tanto para empezar rellenaremos el nombre con “MiClase” y dejaremos en el selector “NSObject” por simplificar la primera clase.
Una vez rellenado este paso del asistente pulsamos en Next y nos saldrá el dialogo para indicar donde queremos guardar la nueva clase:

 Seleccionaremos la carpeta donde se guardará la clase en la parte superior y en la inferior indicaremos el grupo, que es la manera que tiene de denominar Xcode las carpetas virtuales dentro del proyecto. Dentro de la carpeta del proyecto tenemos una carpeta con ese mismo nombre. y es donde se situará los ficheros de la clase.

El target o el destino de la clase, como puede verse en la captura 01_clases es el nombre del proyecto y el target de compilación y ejecución del mismo. Lo dejamos seleccionado y pulsamos en el botón Create.

Esto nos creará los ficheros en el proyecto y nos abrirá automáticamente el fichero de implementación “.m” en el editor, tal como puede verse en la captura:

 También podemos ver cómo en la parte izquierda tenemos dos ficheros correspondientes a la nueva clase. El fichero .h o de cabecera (sí como en C) y el fichero .m de implementación.
Como derivado de C disponemos de los dos ficheros, uno para las definiciones y otro para la implementación.

Veamos el contenido del fichero .h

//
//  MiClase.h
//  01_clases
//
//  Created by pepesan on 10/03/14.
//  Copyright (c) 2014 pepesan. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MiClase : NSObject

@end

En este caso, a parte de los típicos comentarios explicatorios de la clase, tenemos un import
#import <Foundation/Foundation.h>
Que permite importar, como el C, un fichero de cabecera de una biblioteca de sistema, de ahí los <>, en este caso la biblioteca Fundation. Esta biblioteca es la que dispone de la mayor parte de las clases de objetos de Objective C por lo que deberemos importarla siempre.

En el fichero de cabecera, el .h, la clase se enmarca entre el  @interface  y el      @end

Después del @interface se coloca el nombre de la clase, en este caso Miclase, seguido de un : y el nombre de la clase padre en este caso  NSObject .

Por otra parte en el fichero .m, el de implementación nos encontramos con lo siguiente:

#import “MiClase.h”
@implementation MiClase

@end

De la misma manera deberemos importar el fichero de cabecera de la clase:


#import “MiClase.h”

Y la implementación estará enmarcada entre las anotaciones @implementation  , seguido del nombre de la clase Miclase y terminando con el @end .

Objetos

A continuación veremos con instanciar objetos en Objetive C.

Instanciación de Objetos

Para instanciar un objeto de una clase es necesario importar el fichero de cabecera desde el fichero en el cual queramos usar la clase.
En este caso podríamos en el fichero main.m, incluir por encima de la función main lo siguiente:

#import “MiClase.h”
De este modo indicamos al fichero que importe dicha clase, a continuación dentro de la función main podremos realizar la declaración de un objeto:
MiClase *objeto;
Como puede verse primero se escribe la clase a la que va a pertenecer dicho objeto y luego el nombre del objeto, con un * delante, aquellos que conozcan C o C++ verán claramente que se trata de un punto al objeto, en el momento de la declaración dicho puntero apuntará a nil que es como se llama en Objective C a null. A continuación podremos inicializar el objeto:

objeto=[[MiClase alloc] init]; 
esto puede parecer un poco extraño al principio pero leyéndolo con detenimiento tiene sentido la sentencia. 
Lo primero de todo es que al ser una inicialización es una asignación por lo que colocamos en la parte izquierda el nombre del objeto que deseamos inicializar. En la parte derecha de la sentencia vemos dos conjuntos de corchetes, empezamos por el más interno:

[MiClase alloc]
De esta manera indicamos que queremos reservar memoria para el objeto algo muy parecido a un new en Java o un alloc en C. En todos los casos se indica que queremos reservar memoria y el nombre de la clase.

La definición de la función alloc es la siguiente:

– (id) alloc;   

El tipo de dato id es una representación de un NSObject *, pero no es necesario poner el * en este caso, ya que se sobreentiende. Sería lo más parecido a que una función Java devolviera this, refiriéndose a la clase Object .

Se ejecuta el método de la clase alloc  esta es la primer sorpresa en Objetive C. Para ejecutar métodos, que se denomina paso de mensajes en Objective C,  se coloca el nombre de la clase un espacio y a continuación el nombre del método que se desea ejecutar, todo ello rodeado de los corchetes. 

Para ejecutar métodos estáticos, es exactamente igual, salvo que en vez de poner el nombre de la clase se indica el nombre de la clase.
Una vez ya reservada la memoria del objeto es necesario inicializarlo mediante su constructor, que en Objective C, se llama  init y se vuelven a colocar los corchetes antes del “objeto” y después del init .

La declaración de la función init  es la siguiente:

– (id) init; 

Como en el caso anterior también devuelve id .

Nota de codificación: Prueba a escribirlo de la siguiente manera:

  • primero hay que declarar el objeto
  • escribe el nombre de la clase, verás que Xcode te ayuda a rellenarlo, según vas pulsando se va acercando a la clase que buscas, cuando la tengas seleccionado, pulsa enter
  • no te olvides de poner el * entre la clase y el nombre del objeto. Si no lo haces Xcode te saltará un aviso de que no lo has puesto y cómo arreglarlo, poniéndolo XD
  • escribe el nombre de la variable del objeto
  • luego escribe el =
  • Luego pon un abre corchete [
  • Escribe el nombre de la clase, verás que Xcode te ayudará a rellenarla y te aparecerá el corchete de cierre en un tono de gris, como si no estuviera escrito todavía pero que con un gesto podríamos ponerlo, esto se ve más adelante.
  • pon un espacio y una a, verás que Xcode también completa los nombres de métodos
  • selecciona alloc pulsando enter
  • pulsa el botón derecho del teclado o el tabulador, verás como se escribe finalmente el cierra corchete, poniéndolo el color negro definitivo
  • escribe in, verás que sale el método init
  • pulsa enter y se escribirá el método completo
  • escribe un cierra corchete y verás como justo delante del nombre de la clase 
  • pon el ; al final
Como verás el Xcode nos ayuda bastante a buscar los nombres del las clases objetos y métodos. Si sigues esta guía de pasos tendrás menos problemas al codificar y cometerás menos fallos de escritura. 
El constructor init es el constructor principal de todas las clases Objective C. La norma dice que todos ellos deben empezar el nombre con la palabra init en minúsculas. 
Como vemos los nombres de clases siguen la nomenclatura CamelCase, con alguna excepción. Todas las palabras que compongan el nombre deberán llevar la primera letra en mayúscula y el resto en minúscula, de ahí el nombre MiClase. Muy similar a como se hace en Java.
La excepción a esta regla es que las clases Objective C suelen disponer de un prefijo que indica la compañía que la ha realizado. En la mayor parte de las clases de la biblioteca Fundation empiezan por NS, referiéndose a la empresa Next Step creadora de esta biblioteca.

Propiedades de Objetos

Inclusión de Atributos (propiedades)

Para incluir un atributo hay muchas maneras de realizarlo pero la más sencilla es su inclusión en el fichero de cabecera .h, dentro de la definición de la clase, veamos un ejemplo:
@property int propiedad;
como puede verse se antepone a la definición del atributo la anotación  @property  y después se declara normalmente la variable, poniendo primero el tipo y luego el nombre de la variable. Lo mismo se haría con los objetos de clase.

Características de una propiedad (property attributes)

  • getter: permite definir el nombre del método getter, de la siguiente manera: getter=nombreDeMetodo
  • readwrite: por defecto las propiedades en Objective C son de lectura escritura.
  • readonly: para aquellas propiedades que se tienen que comportar como de sólo lectura.
  • copy: permite realizar una copia del objeto cada vez que se asigne a otra variable.
  • nonatomic: todas las variables de Objetive C son atómicas, en el sentido de comunicación entre hilos de ejecución. Es decir, significa que dos hilos intentan realizar un incremento sobre una variable, no haría problema a la hora de sincronizar esos dos hilos para que en ella se puedan actualizar los valores. Si queremos que las variables no se comporten así las definiremos como nonatomic. Al no necesitar sincronizar los accesos a las variables el rendimiento de la aplicación mejor.
  • strong: serán punteros responsables o poseedores de una variable. Por lo tanto si se elimina ese puntero y no hay otra variable strong sobre ese conjunto de datos, se procederá a una liberación automática de la memoria que ocupaba ese dato. Se solía llamar antes retain.  Sólo funciona con objetos. Más información: Referencia de Apple.
  • weak: es el caso contrario a strong, no pasa nada si se libera una variable weak. Se pueden llamar también punteros temporales.
Ejemplo de propiedad que es una cadena de caracteres:
@property (nonatomic, strongNSString *propiedadcadena;

Uso de propiedades de un objeto

La comparación con Java de la anterior sentencia es la definición de un atributo publico. Por lo que podría usarse como tal después de inicializar el objeto, incluyendo el código en el main.m lo siguiente:
objeto.propiedad=1;
como puede verse es una utilización más sencilla del atributo muy similar a Java. Primero se pone el nombre del objeto seguido de un punto y el nombre del atributo o propiedad como se dice en Objective C. Un igual y un valor y ya tenemos una asignación de un valor a una propiedad del objeto, que por supuesto podemos sacarla por la consola:
NSLog(@”%d”, objeto.propiedad);

Getters y Setters, paso de mensajes relacionados con una propiedad

Una vez definida la propiedad podremos hacer uso automático de los setter y getter de la siguiente manera, empezando por el setter:
[objeto setPropiedad:1];

De las misma manera que ejecutamos métodos de un objeto, o paso de mensajes en Objective C, ponemos el nombre del objeto, un espacio, set y el nombre de la propiedad un dos puntos para pasar un parámetro,  ojo no flipes demasiado, y luego el valor o variable que le queremos pasar todo por supuesto rodeado de corchetes.

Funciona de una manera similar a un JavaBean, el nombre siempre es set en minúscula seguido del nombre de la variable con la primera letra mayúscula y el resto en minúsculas, CamelCase otra vez.
Todos los métodos en Objective C se escriben de esta manera, así son más fáciles de recordar y escribir.

Con el anterior ejemplo hemos colocado el valor 1 en la propiedad del objeto.

Veamos ahora el getter:

[objeto propiedad]

de esta manera ponemos entre corchetes el nombre del objeto, un espacio y el nombre de la propiedad.

A mi me sigue pareciendo más cómodo el uso del punto, pero para aquellas propiedades que sean privadas será más apropiado llamar al getter en su lugar.

La función nos devolverá el valor de la propiedad, otra diferencia con los JavaBeans. Aquí no se pone el get delante del nombre de la propiedad.

De esta manera para sacar por consola el valor almacenado en la propiedad pondremos lo siguiente:

NSLog(@”%d”,[objeto propiedad]);

Métodos de Clase

Inclusión de un método

Como en C++ será necesario incluir la definición del método en el fichero de cabecera .h, veamos un ejemplo sencillo:
– (void) diAlgo;
Como podemos ver ponemos un – seguido de entre paréntesis el tipo del dato que se devuelve, en este caso void (nada) seguido del nombre de la función diAlgo y finalizando un ;

Implementación 

A continuación deberemos realizar la implementación del método en el fichero .m, de una manera similar a la siguiente:

– (void) diAlgo{
    //Aquí va el código del método

}

La implementación del método es igual a la definición salvo por los {} que son los que incluirán el código que deberá ejecutar el método al ser invocado.

Haremos que por ejemplo escriba algo en la consola:

NSLog(@”Algo”);

De esta manera el método completo quedará de la siguiente manera:

– (void) diAlgo{
    
    //Aquí va el código del método
    NSLog(@”Algo”);

}

Invocación

Para invocar al método será tan sencillo como lo hemos realizado anteriormente con el método alloc, pero esta vez escribiremos:
[objeto diAlgo];
Así al ejecutarlo veremos que escribe por consola algo similar a esto:
2014-03-10 06:20:43.356 01_clases[6043:303] Algo

Paso de Parámetros

De cara a pasar parámetros es una de las cosas más confusas al principio de aprender Objective C debido a su sintaxis, veamos un ejemplo con una definición en el .h:
– (void) incremento:(int)inc;
Como podemos ver la definición es prácticamente la misma, salvo por el parámetro.
Después del nombre del método ponemos un : seguido del tipo del dato del parámetro entre (), en este caso un número entero, seguido del nombre interno de la variable del parámetro, en este caso inc y por supuesto finalizado por un ;
En este método intentaremos realizar un incremento de la propiedad con el valor que nos pasen como parámetro.
En el fichero de implementación ocurrirá algo similar:
– (void) incremento:(int)inc{
    _propiedad+=inc;
}
La definición dela función será igual que en el fichero de cabecera salvo por los {}

Acceso a propiedades desde la implementación de la clase

Y dentro de los paréntesis incluimos el código de la implementación:
_propiedad+=inc;
Como puede verse si queremos tener acceso a ls propiedades definidas en la clase, deberemos anteponer al nombre de la propiedad un _
También podríamos hacer lo siguiente:
self.propiedad+=inc;
self es lo más parecido al this de Java. Se refiere al objeto de la clase, seguido de un punto para acceder a la propiedad. En este caso estamos haciendo uso de un operador de asignación e incremento       
+= para incrementar la variable con el valor de inc.
Como puede verse es un poco engorroso en comparación con Java al tener que incluir el _ o el self 
Pero hay una posibilidad para simplificar el proceso, incluyendo lo siguiente en la implementación de la clase:
@synthesize propiedad;
De esta manera podremos acceder directamente a la propiedad simplemente utilizando su nombre en cualquier parte de a implementación:
propiedad+=inc;

Resumen de código

Resumiendo los ficheros quedarían de la siguiente manera, empezando por el .h:
#import <Foundation/Foundation.h>
@interface MiClase : NSObject
@property int propiedad;
– (void) diAlgo;
– (void) incremento:(int)inc;
@end
Y el fichero .m:
#import “MiClase.h”
@implementation MiClase
@synthesize propiedad;
– (void) diAlgo{
    
    //Aquí va el código del método
    NSLog(@”Algo”);
}
– (void) incremento:(int)inc{
    propiedad+=inc;
}
@end

Invocación del método con un parámetro

De esta manera con el método definido e implementado sólo haría falta invocarlo desde el main.n, sobre el objeto ya inicializado:
[objeto incremento:3];
 Se coloca el nombre del objeto, un espacio, el nombre del método, : y el valor o variable que se le quiere pasar por parámetro, todo metido entre [] y un ; al final.
Al intentar sacar el valor de la propiedad por consola veremos que se ha incrementado su valor en 3:
NSLog(@”%d”,objeto.propiedad);

Devolviendo valores

Para que pueda ser un función completa deberíamos ser capaces de devolver un valor para ello será necesario indicar el tipo de la variable a devolver entre los () de a definición y la implementación:
– (int) suma:(int)sumando;
y la implementación:
– (int) suma:(int)sumando{
    return propiedad+sumando;
}
Como puede verse utilizamos con el C la palabra reservada  return  para indicar que queremos termine la ejecución del método y queremos devolver un valor. 
Para recoger el valor basta colocar una sentencia se asignación, donde en la parte de la izquierda colocamos la variable donde queremos almacenar el valor devuelto, en el ejemplo, lo incluimos en el main.m:
int i= [objeto suma:3];

Varios parámetros devolviendo un valor

Para poner un ejemplo más completo veremos un método que devuelve un valor y al que se le pasa más de un parámetro, en el ejemplo serán dos parámetros, empecemos por el fichero de cabecera:
– (int) suma:(int)sumando withInt:(int)otro;
Como se puede ver se separa por un espacio se indica un nombre complementario a la función indicando el tipo del dato que se le pasa, de manera informativa, luego se pone un :, entre paréntesis el tipo del dato, en este caso un entero y el nombre de la variable interna del método, antes del ;
Veamos la implementación en el fichero .m:
– (int) suma:(int)sumando withInt:(int)otro{
    return propiedad+sumando+otro;
}
Con la misma cabecera y con el return de la suma de la propiedad con los parámetros.
Sólo faltaría la invocación del método desde el objeto en el main.m:

int k=[objeto suma:10 withInt:10];

Metodos estáticos

Los métodos estáticos son aquellos que no necesitan tener inicializado un objeto de la clase para poder invocarlos, en Java son los métodos static.

Para definir un método estático, se diferencia por el uso del + antes de la definición del método en vez del -, veamos un ejemplo, definido en el .h:

+ (void)estatico;

Ahora su implementación en el .m:

+ (void)estatico{
    NSLog(@”Estático”);

}

Un método sencillo 🙂

Ahora su invocación desde el main.m:

[Clase estatico];

Como puede verse se utiliza el nombre de la clase en vez del nombre del objeto, al como ocurre con el método alloc.

Llamar a los métodos del padre (herencia)

En un determinado momento nos puede llegar a interesar llamar en vez de a la implementación de un método hecho en la clase que estoy creando nueva, llamar al método de mi clase padre, para ello deberemos usar  lo siguiente:
[super nombreDelMetodo];

Llamar a los métodos de la propia clase

En un determinado momento nos puede llegar a interesar llamar a un método hecho en la clase que estoy creando nueva, para ello deberemos usar  lo siguiente:
[self nombreDelMetodo];

Contructores (init)

Si queremos inicializar las propiedades de un objeto cuando se iniciativa es necesario crear una implementación del método init en la clase.

Dentro del fichero de cabecera deberemos introducir lo siguiente:

– (id) init;

Una vez definida el método debemos realizar la implentación, en el fichero .m, de una manera similar a la siguiente:

– (id)init {
    self = [super init];
    
    if (self) {
        //Aquí se inicializan las variables
        propiedad=0;
    }
    
    return self;

}

Como puede verse en el ejemplo el método devuelve self es decir el mismo objeto. Es una buena práctica llamar al constructor del padre antes de nada y luego comprobar si el objeto se ha inicializado apropiadamente con un if. Si eso es así, dentro del código del if, introducimos las inicializaciones pertinentes.

Contructores con parámetros (initWith)

Es posible que nos pueda interesar crear un constructor con parámetros, para ello llamaremos al método initWith y algo más en el nombre indicativo de que queremos hacer un init con algo más indicativo del tipo de datos que vayamos a utilizar en la inicialización. Esto se hace para que cuando se vaya a utilizar este método en la inicialización de un objeto, Xcode filtre los distintos constructores y ayuden al programador a escribirlos.
Por lo demás será un método normal, como los que hemos mencionado anteriormente. En el fichero .h escribiremos la definición:
– (id) initWithInt:(int)i;
Y en el fichero de implementación, .m, lo siguiente:
– (id) initWithInt:(int)i{
    self = [super init];
    
    if (self) {
        propiedad=i;
    }
    
    return self;
}

Para poder llamar a ese contractos en el main.m pondríamos algo similar a esto:

        MiClase *objeto2=[[MiClase alloc]initWithInt:3];
        

        NSLog(@”%d”, objeto2.propiedad);

Otras maneras de inicializar propiedades

Si bien el uso de constructores está bastante extendido en la comunidad de programadores, hay otras maneras de inicializar las propiedades. La más sencilla es la sobrecarga del setter, veamos un ejemplo:
– (NSObject *)propiedad {
    if (!propiedad) {
        propiedad = [[NSObject alloc] init];
    }
    
    return propiedad;
}

De esta manera conseguimos que cada vez que se va a acceder a dicha propiedad se inicialice el objeto en el caso de que no haya sido inicializado previamente.

Visibilidad de métodos y propiedades

Por defecto todos lo métodos y propiedades incluidos en el fichero de cabecera serán públicos, pero podemos incluir métodos y propiedades privadas en la implementación de la clase. Veamos un ejemplo de inclusión de una propiedad privada, en el fichero .m:
@implementation MiClase{
    @private int privada;
}
@end
De esta manera conseguimos que dicha propiedad no sea visible desde la invocación del objeto, pero podemos seguir utilizándola desde cualquier método de la clase simplemente por su nombre:
privada=0;
Para incluir un método privado basta con no incluirlo en el fichero de cabecera y sólo incluir el método en el fichero de implementación:
– (void) privado{
    NSLog(@”desde el método privado”);
}

Resumen

Hemos visto cómo definir Clases, con sus propiedades y métodos, así como la declaración, inicialización de un objeto y el acceso a sus propiedades y métodos.

Ejercicios propuestos

  • Crea un nuevo proyecto
  • Crea una nueva Clase llamada MiClase
  • Declara un objeto de la clase MiClase en el main.m
  • Inicializa dicho objeto.
  • Incluye una propiedad en la clase
  • Utiliza esa propiedad desde el main.m
  • Crea un método nuevo al que no le pases ningún parámetro ni devuelva nada en la clase
  • Invoca ese nuevo método desde el main.m
  • Crea un método nuevo al que le pases un parámetro pero no devuelva nada en la clase
  • Invoca ese nuevo método desde el main.m
  • Crea un método nuevo que haga la suma de dos números y devuelva el resultado
  • Invoca ese nuevo método desde el main.m
  • Crea una clase Cliente: con los siguientes datos: código de cliente, nombre, tlf y dirección. 
  • Inicializa un objeto de tipo Cliente en el main.m
  • Crea un constructor con parámetros y sin parámetros para la clase Cliente
  • Utiliza el constructor con parámetros  para inicializar un objeto de la clase Cliente en el main.m

Curso de Objective C: Estructuras de Control: if-else y Operadores de comparación y Lógicos

IF

Como en todos los lenguajes de programación es necesario disponer de estructuras de control que permitan gestionar el flujo de la aplicación, para ellos contamos con varias herramientas empezaremos con el if.

La sentencia condicional por antonomasia, veamos su estructura básica y algunos ejemplos.

        /*
         if(condición){
            Código si cumple la condición
         }else{
            Código si no cumple la condición
         }
        */
Como podemos ver tenemos una condición a cumplir y el código en el caso de que cumpla la condición y en el caso de que no lo haga. 
Por supuesto no es necesario disponer siempre de un else en la sentencia.

        int i=1;
        if(i<2){
            NSLog(@”i es menor que 2!”);
        }

Aunque lo más normal es que sea completa como en el siguiente ejemplo:

        if(i<2){
            NSLog(@”i es menor que 2!”);
        }else{
            NSLog(@”i no es menor que 2!”);
        }
      
También disponemos de la posibilidad de tener un else if con una condición extra:
        i=3;
        
        if(i<2){
            NSLog(@”i es menor que 2!”);
        }else if (i==2){
            NSLog(@”i es igual a 2!”);
        }else{
            NSLog(@”i es mayor que 2!”);
        }
      
Como en otros lenguajes tenemos la posibilidad de realizar una forma apocopada del if, en este caso estamos realizando una asignación sobre una variable en base a una condición, que el valor de una variable booleana:
        // if acortado
        BOOL unavar=true;
        int valordevuelto = unavar ? 15 : 20;
        NSLog(@”%d”,valordevuelto);

        //if sin abreviar

        if(unavar==true){
            valordevuelto=15;
        }else{
            valordevuelto=20;
        }

        NSLog(@”%d”,valordevuelto);

 Operadores de comparación y lógicos

Como en otros lenguajes es necesario conocer los operadores típicos de las condiciones, como son los operadores de comparación y los lógicos en base a las “tablas de verdad” de las operaciones principales, AND, OR y NOT.

        /*
         * Operadores de comparación
         
         < menor que
         > mayor que
         <= menor o igual
         >= mayor o igual
         == igual
         != distinto
         
         * Operadores lógicos
         
         AND &&
         
         p  q   p AND q
         0  0       0
         0  1       0
         1  0       0
         1  1       1
         
         OR  ||
         
         p  q   p OR q
         0  0       0
         0  1       1
         1  0       1
         1  1       1
         
         NOT !
         p  NOT p
         0      1
         1      0
         
         
        */
Aquí tenemos un ejemplo de uso de una doble condición con el operador AND.

        i=2;
        int j=2;
        if (i<=2 && j<4) {
            NSLog(@”Cumple las dos condiciones”);

        }

En el siguiente punto veremos otras sentencias de control.

Licencia Creative Commons

Suscríbete al Boletín

Si quieres estar al tanto de las novedades del blog, ya sabes :)
* = campo obligatorio

powered by MailChimp!

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. ACEPTAR

Aviso de cookies