iOS para desarrolladores .NET: Clases en Objetive-C parte 2

jueves, 29 de enero de 2015


En el anterior artículo vimos como se deninen las clases y propiedades comparado con C#.

En este artículos vamos a ver de que forma definimos en una clase como se pueden construir las instancias de objeto.

Constructores, inicializadores

Vamos a ver estos conceptos como se aplican en C# y luego en Objetice-C.

C#

En C# existen un constructor por defecto, podemos crearnos uno con paramétros también para configurar el objeto que estamos creando.

public class Product
{

    //Constructor por defecto, todos las clases lo tienen
    //no es necesario crearlo salvo que queramos hacer algo
    //en el momento de construir el objeto
    public Product()
    {

    }

    //Constructor con parámetros, si no lo creamos lo crea el compilador
    public Product(string title, string color)
    {

    }
}


Luego el objeto se puede crear así:

    //constructor por defecto
    Product product = new Product();

    //contructor con parámetros
    Product product = new Product("Nike Dunk Low", "Rojo");


También existen inicializadores de objeto, donde sin necesidad de constructor podemos crear el objeto atacando directamente a las propiedades. En el proceso de creación se invoca el constructor sin parámetros.
    Product product = new Product
        {
            Title = "Nike Dunk Low"
            Color = "Rojo"
        };

Objetive-C

En Objetive-C no existe el concepto constructor, existe el concepto de inicializador pero salvando las diferencias, la idea se parece más al constructor de C#.

Todas las clases tienen un inicializador por defecto llamado init, podemos redefinirlo si queremos hacer algo en el momento de la inicialización del objeto pero sino no es necesario. El inicializador se tine que declarar primero en el .h (cabecera) y se tiene que implementar en el .m (implementación). Cuando definimos un inicializador debemos invocar el inicializador de la clases base y si todo ha ido bien ya podemos inicializar nuestro objeto.

//Fichero de cabecera
@interface Product : NSObject

  @property(strong,noanatomic) NSString * title;

  // declaramos el inicializador
  -(id)init;
@end

//Fichero de implementación
@implementation Product
    -(id)init{
        //inicializamos la clase base y si es true, que es como indicar si es distinto de nil (null)
        if ( self = [super init] ) {
            //inicializamos el objeto
        } else
        return nil;
    }
@end


El menos o guión al princpio de la declaración del inicializador indica que es un inicializador de instancia, este concepto lo veremos más detenidamente con los métodos en otro artículo. Y el Id es el tipo de objeto devuelto, Id quiere decir cualquier tipo de objeto, como si hubieramos puesto como resultado de una fucnión object en C#. Podríamos haber especifícado Product como tipo de respuesta del inicializador pero esto puede ser problematico. En Objetive-C los inicilizadores se heredan, entonces se podría dar el caso de tener una clase B que hereda de una clase A, si tenemos un inicilizador específico solo en la clase base y lo utilizamos para inicilizar la clase deribada, entonces nos devolvería la clase base A cuando queremos inicilizar la deribada B, si ponemos Id lo hace correctamente.

Podemos tener inicializadores con parámetros también y la sintaxis es un poco rara y diferente a .NET o Java. Cuando un inicializador tiene parámetros el nombre del inicilizador tiene que hacer referencia a todos los parámetros y se va intercalando con ellos. Imaginemos siguiendo el mismo ejemplo que estamos viendo hasta ahora, tenemos una clase product y vamos a crear un inicializador con título y color, el nombre del método tiene que empezar con initWith y tiene que hacer referencia a todos los parámetros entonces podría ser así initWithTitleAndColor y ahora falta intercalar los parámetros y separar el nombre del método que pertenece a cada parámetro con dos puntos verticales, vamos a ver el ejemplo

//Fichero de cabecera
@interface Product : NSObject

  @property(strong,noanatomic) NSString * title;

  -(id)initWithTitle: (NSString *) title AndColor: (NSString *) color;
@end

//Fichero de implementación
@implementation Product
    -(id)initWithTitle: (NSString *) title AndColor: (NSString *) color{
        //inicializamos la clase base y si es true, que es como indicar si es distinto de nil (null)
        //entre corchetes ponemos la invocación de un método, en Objetive-C se llama mensaje
        if ( self = [super init] ) {
            //inicializamos el objeto
            _title = title;
            _color = color;
        } else
        return nil;
    }
@end


Los parámetros van precedidos del tipo entre paréntesis y si el tipo es un objeto no primitivo debe llevar el asterisco indicando que es un puntero. Entonces nuestro nombre de inicilizador nos queda así initWithTitle:AndColor:, y así aparecerá en la ayuda de Xcode documentados los inicilizadores o métodos, ambos tienen la misma sinta xis.

Ahora que ya sabemos como definir los inicilizadores, nos falta ver como se crean los objetos usando los inicilizadores.

Podemos utilizar una sintaxis parecida a C# (Product product = new Product())

    Product * product = [Product new];


Así se ejecuta el inicializador por defecto, si queremos poder ejecutar inicializadores con parámetros tenemos que utilizar otra sintaxis diferente.

De esta otra forma, más habitual en Objetive-C, primero hay que reservar espacio en la memoria mediante la instrucción alloc y después se inicializa el objeto utilizando algunos de los inicializadores de la clase.

    Product * product = [[Product alloc] initWithTitle:@"Nike Dunk Low" andColor:@"Rojo"];
Tipos de Inicializador
Una clase puede tener varios inicilizadores pero hay uno que es que cubre todos los parámetros y el que hace el trabajo de inicilizar la clase base y las variable o propiedades del objeto, este es conocido como inicializador designado, el resto pueden omitir parámetros y lo que hacen es invocar el inicilizador designado asignando valores por defecto, a estos se les conoce como inicilizadores de conveniencia o secundarios.

Vamos a ver como podríamos tener nuestro ejemplo con varios inicializadores.

//Fichero de cabecera
@interface Product : NSObject

  @property(strong,noanatomic) NSString * title;

  //inicializador designado
  -(id)initWithTitle: (NSString *) title AndColor: (NSString *) color;

  //inicializadores de conveniencia
  -(id)initWithTitle: (NSString *) title;
  -(id)init;

@end

//Fichero de implementación
@implementation Product
    //inicializador designado
    -(id)initWithTitle: (NSString *) title AndColor: (NSString *) color{
        if ( self = [super init] ) {
            //inicializamos el objeto
            _title = title;
            _color = color;
        } else
        return nil;
    }

    //inicializadores de conveniencia
    -(id)initWithTitle: (NSString *) title {
        //self es como this en C#
        return [self initWithTitle:title andColor:nil]
    }

    -(id)init{
         //self es como this en C#
        return [self initWithTitle:nil andColor:nil]
    }
@end


Como podéis ver solo el inicalizador designado es el encargado de inicializar la clase base y las propiedades del objeto, los inicilizadores de conveniencia invocan el designado pasando los valores que les llegan por parámetro y de los que no, inicializa con los valores por defecto.

Resumen

En este artículo hemos visto de que forma se definen inicializadores en las clases de Objetive-C y como se invocan estos inicializadores. Hemos repasado la sistaxis que es un poco peculiar y por último hemos visto que hay dos tipos de inicilizadores, el designado y los de conveniencia.

Libros relacionados

iOs Programming for .Net Developers

iOS Programming: The Big Nerd Ranch Guide

Objective-C Programming: The Big Nerd Ranch Guide

No hay comentarios:

Publicar un comentario