VISITAS:

martes, 18 de agosto de 2015

SWIFT (VII) : Clases y Objetos

Swift es un lenguaje orientado a objetos para desarrollar aplicaciones iOS y OSX.
No es el objetivo de este capítulo explicar los conceptos de orientación a objetos (para eso existen multitud de libros y artículos), sino explicar cómo estos conceptos se implementan con swift.

Clases

Una clase se define de la siguiente forma:

class NombreDeLaClase : ClasePadre {
    // propiedades
    // métodos de instancia
    // metodos de clase
}

Las propiedades son variables y constantes. Se declaran de la misma forma que las variables y constantes en swift, es decir, con var y let.
Los métodos de instancia son funciones que se invocarán a través de un objeto de la clase. Se declaran de forma similar a las funciones de swift, es decir, con func.
Los métodos de clase son comunes a toda la clase y no se necesita un objeto para invocarlos (son similares a los métodos estáticos de otros lenguajes). Se declaran como funciones normales, pero con class func.

Veamos un ejemplo:

class GraphicObject {
    var x : Float = 0
    var y : Float = 0
    func show() {
        println("x=\(x), y=\(y)")
    }
    class func getMaxWidth() -> Float {
        return 240.0
    }
}

Clase derivada:

class Rectangle : GraphicObject {
    var width : Float = 0
    var height : Float = 0
}

Objetos

Declaración de un objeto:

var obj : Rectangle = Rectangle()

Constructores

En swift, una forma más correcta de llamar a los constructores sería: inicializadores.
Declaración del constructor (nótese que no se pone func en el constructor):

class Rectangle : GraphicObject {
    var width : Float = 0
    var height : Float = 0
    init( w : Float, h : Float ) {
        width = w
        height = h
    }
}

Cuando se instancia el objeto hay que pasar los argumentos que necesita el constructor (si no se pasan los argumentos adecuados el compilador da un error, además, los argumentos deben pasarse nombrados obligatoriamente):

var obj = Rectangle( w: 20.0, h: 10.0 )

Como se puede ver, los constructores no son funciones normales: no empiezan con func; hay que nombrar los argumentos obligatoriamente en la llamada; tienen un nombre especial (init).

Deinicializadores

Un deinicializador (destructor en otros lenguajes) se invoca justo antes de que el objeto se destruya. La destrucción del objeto ocurre cuando el recolector de basura así lo decide.

La sintaxis del deinicializador es especial, aunque es similar a la de un inicializador sin parámetros:

class Rectangle : GraphicObject {
    var width : Float = 0
    var height : Float = 0
    init( w : Float, h : Float ) {
        width = w
        height = h
    }
    deinit {
        // labores de limpieza del objeto
        println("cleanup")
    }
}

Llamada a métodos y acceso a propiedades

El acceso a las propiedades y métodos de un objeto es muy sencillo en swift (similar a otros lenguajes):

var a = obj.width
obj.width = 70.0
obj.show()

Para llamar a un método de clase:

Rectangle.getMaxWidth()

Propiedades almacenadas y calculadas

Las propiedades pueden ser de uno de los siguientes tipos: almacenadas o calculadas.
Las propiedades almacenadas son las que hemos visto hasta ahora, contienen su valor en una variable o una constante.
Una propiedad calculada es el resultado de un cálculo o una lógica. Para implementar variables calculadas tenemos que declarar un método getter y (opcionalmente) un método setter, para leer y escribir el valor de la variable respectivamente. La variable en sí misma podría incluso no existir.

class Rectangle : GraphicObject {
    .......
    var area : Float {
        get {
            return w * h
        }
    }
}

Se puede declarar igualmente el setter con la palabra reservada set.

class Rectangle : GraphicObject {
    .......
    var widthInInches : Float {
        get {
            return width / 2.54
        }
        set(inches) {
            width = inches * 2.54
        }
    }
}

Self

En swift, al igual que en otros muchos lenguajes orientados a objetos, desde dentro de los métodos de instancia se puede acceder al propio objeto. Para ello, se utiliza self (similar a this en otros lenguajes). No es obligatorio utilizar self, pero sí es recomendable para aclarar. Aunque en algunos casos sí es obligatorio, por ejemplo cuando algún nombre de parámetro de función coincido con el nombre de una propiedad:

    func setValues(width : Float, height : Float) {
        self.width = width
        slef.height = height
    }

Sobreescribir métodos

La herencia de clases supone que la clase hija hereda todas las propiedades y métodos de la clase padre, pero además, la clase hija puede añadir nuevas propiedades y métodos, ampliando así la funcionalidad de la clase padre. Pero otra manera de ampliar (o especializar) la funcionalidad de la clase padre es sobreescribiendo métodos en la clase hija:

override func show() {
    println("width=\(width), height=\(height)")
}

Desde un método sobreescrito se puede invocar al método original de la clase padre de la siguiente forma:

override func show() {
    super.show()
    println("width=\(width), height=\(height)")
}

Inicialización de subclases

La inicialización de un objeto se realiza en el inicializador de la clase, como ya hemos visto. En el caso de subclases, la clase hija es responsable de llamar al inicializador de la clase padre:

init( x: Float, y : Float, w : Float, h : Float ) {
    width = w
    height = h
    super.init(x : x, y : y)
}

La llamada al constructor de la clase padre se puede realizar en cualquier punto del inicializador de la clase hija (en algunos lenguajes se obliga a llamarlo al principio).




No hay comentarios:

Publicar un comentario