Blog de Desarrollo en Swift para Plataformas Apple

Swift – Métodos de Instancia y de Tipo

Get real time updates directly on you device, subscribe now.

En este nuevo Tutorial Swift aprenderemos acerca de los métodos de instancia y de tipo. Los métodos son funciones que están asociadas con un tipo en particular. Las clases, estructuras y enumeraciones, todas, pueden definir métodos de instancia, que encapsulan tareas y funciones específicas para trabajar con una instancia de un tipo dado. Las clases, estructuras y enumeraciones también pueden definir métodos de tipo, que se asocian con el tipo en sí.

[anuncio_b30 id=1]

Se que no suena del todo claro lo antes dicho, así que permítanme intentar desarrollar mejor estas ideas a base de ejemplos.

Métodos de instancia

Los métodos de instancia son funciones que pertenecen a instancias de una clase, estructura o enumeración, estas aportan la funcionalidad de las instancias, ya sea proporcionando formas de acceder y modificar las propiedades, o proporcionando funcionalidad relacionada con el propósito de la instancia. Ejemplo:

class Counter {

    var count = 0

    func increment() {

        ++count

    } // increment

    func incrementBy(amount: Int) {

        count += amount

    } // incrementBy

    func reset() {

        count = 0

    } // reset

} // Counter

…en este código hemos creado la clase Counter, tres métodos de instancia y una propiedad. Más allá de que se les llama métodos de instancia en lugar de funciones, nada de esto es nuevo, ya lo hemos visto en otros artículos de este Curso Swift.

La propiedad self

Cada instancia cuenta con una propiedad implícita llamada self, que es exactamente equivalente a la propia instancia. Utilizamos la propiedad self para hacer referencia a la instancia actual dentro de sus propios métodos de instancia, self vendría a ser como el this de C++ o Java.

El método increment() en el ejemplo anterior se podría haber escrito así:

func increment() {

   self.count++

} // increment

…escribir self en este caso no es necesario ya que el compilador asume que se está haciendo referencia a una propiedad de la clase donde se encuentra este método de instancia.

Modificación de tipos por valores

Las estructuras, las enumeraciones y las tuplas son tipos por valor o Value Types en ingles. Sin entrar en muchos detalles (este tema lo tocaremos en otro Curso Swift) digamos que esto significa que almacenan una copia única de los datos que engloban y como es de esperar estas características establecen ciertas particularidades en estos tipos. Veamos un ejemplo de esto:

//: Playground - noun: a place where people can play

import UIKit

class Crane {

    var craneName: String = "None"

} // Crane

struct DataStruct {

    var someNumber: Int = 0

} // DataStruct

enum BoomLevel {

    case High
    case Half
    case Low

} // BoomLevel

//--------------------------------------------------------------------------------------

var MyCrane: Crane = Crane()

MyCrane.craneName = "Crane - Backyard"

print("The name of the crane is: \(MyCrane.craneName)")

//--------------------------------------------------------------------------------------

var MyStruct: DataStruct = DataStruct()

MyStruct.someNumber = 10

print("The property value of the structure is: \(MyStruct.someNumber)")

//--------------------------------------------------------------------------------------

var MyEnum: BoomLevel

MyEnum = BoomLevel.High

print("The value of MyEnum is: \(MyEnum)")

MyEnum = BoomLevel.Half

print("The value of MyEnum now is: \(MyEnum)")

…la salida en pantalla sería:

The name of the crane is: Crane - Backyard
The property value of the structure is: 10
The value of MyEnum is: High
The value of MyEnum now is: Half

De las línea 5 a la 23 tenemos la declaración de la clase Crane, la estructura DataStruct y la enumeración BoomLevel. Luego de la línea 27 a la 51 hacemos uso de estas, creamos instancias de las mismas, las inicializamos y le asignamos un valor, terminamos por imprimir en pantalla los valores añadidos.

[anuncio_b30 id=2]

Hasta aquí todo bien, las tres instancias fueron declaradas como variables, pero ¿qué sucedería si tuviéramos métodos de instancia y estos modificaran el valor de las instancias a las que pertenecen? Aquí algunos cambios:

//: Playground - noun: a place where people can play

import UIKit

class Crane {

    var craneName: String = "None"

    func changeName(newName: String) {

        craneName = newName

    } // changeName

} // Crane

struct DataStruct {

    var someNumber: Int = 0

    func addingOne() {

        someNumber++

    } // changeProperty

} // DataStruct

enum BoomLevel {

    case High
    case Half
    case Low

    func changeLevel(newValue: BoomLevel) {

        switch newValue {

        case High:

            self = Half

        case Half:

            self = Low

        case Low:

            self = Half

        } // switch

    } // changeProperty

} // BoomLevel

//--------------------------------------------------------------------------------------

var MyCrane: Crane = Crane()

MyCrane.craneName = "Crane - Backyard"

print("The name of the crane is: \(MyCrane.craneName)")

MyCrane.changeName("Crane - Buildings")

print("The name of the crane is: \(MyCrane.craneName)")

//--------------------------------------------------------------------------------------

print("")

var MyStruct: DataStruct = DataStruct()

MyStruct.someNumber = 10

print("The property value of the structure is: \(MyStruct.someNumber)")

MyStruct.addingOne()

print("The property value of the structure is: \(MyStruct.someNumber)")

//--------------------------------------------------------------------------------------

print("")

var MyEnum: BoomLevel

MyEnum = BoomLevel.High

print("The value of MyEnum is: \(MyEnum)")

MyEnum.changeLevel(BoomLevel.Half)

print("The value of MyEnum now is: \(MyEnum)")

…la salida en pantalla sería:

Playground execution failed: /var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:23:19: error: cannot pass immutable value to mutating operator: 'self' is immutable
        someNumber++
        ~~~~~~~~~~^
/var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:21:5: note: mark method 'mutating' to make 'self' mutable
    func addingOne() {
    ^
    mutating 
/var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:41:18: error: cannot assign to value: 'self' is immutable
            self = Half
            ~~~~ ^
/var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:35:5: note: mark method 'mutating' to make 'self' mutable
    func changeLevel(newValue: BoomLevel) {
    ^
    mutating 
/var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:45:18: error: cannot assign to value: 'self' is immutable
            self = Low
            ~~~~ ^
/var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:35:5: note: mark method 'mutating' to make 'self' mutable
    func changeLevel(newValue: BoomLevel) {
    ^
    mutating 
/var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:49:18: error: cannot assign to value: 'self' is immutable
            self = Half
            ~~~~ ^
/var/folders/36/gv16k48s4wn_92bbl72jj5f80000gn/T/./lldb/48513/playground385.swift:35:5: note: mark method 'mutating' to make 'self' mutable
    func changeLevel(newValue: BoomLevel) {
    ^
    mutating

…exactamente, hay errores en el código debido a una características propia del lenguaje como lo es el hecho de que ningún método de instancia de una estructura o enumeración puede modificar una propiedad miembro de las mismas, algo que si podemos lograr en una clase. Sin embargo tampoco es imposible de lograr, para ello necesitamos hacer uso de la palabra clave mutating en conjunto a la declaración de cada método de instancia.

[anuncio_b30 id=3]

El código anterior ya corregido quedaría de la siguiente forma:

//: Playground - noun: a place where people can play

import UIKit

class Crane {

    var craneName: String = "None"

    func changeName(newName: String) {

        craneName = newName

    } // changeName

} // Crane

struct DataStruct {

    var someNumber: Int = 0

    mutating func addingOne() {

        someNumber++

    } // addingOne

} // DataStruct

enum BoomLevel {

    case High
    case Half
    case Low

    mutating func changeLevel(newValue: BoomLevel) {

        switch newValue {

        case High:

            self = Half

        case Half:

            self = Low

        case Low:

            self = Half

        } // switch

    } // changeProperty

} // BoomLevel

//--------------------------------------------------------------------------------------

var MyCrane: Crane = Crane()

MyCrane.craneName = "Crane - Backyard"

print("The name of the crane is: \(MyCrane.craneName)")

MyCrane.changeName("Crane - Buildings")

print("The name of the crane is: \(MyCrane.craneName)")

//--------------------------------------------------------------------------------------

print("")

var MyStruct: DataStruct = DataStruct()

MyStruct.someNumber = 10

print("The property value of the structure is: \(MyStruct.someNumber)")

MyStruct.addingOne()

print("The property value of the structure is: \(MyStruct.someNumber)")

//--------------------------------------------------------------------------------------

print("")

var MyEnum: BoomLevel

MyEnum = BoomLevel.High

print("The value of MyEnum is: \(MyEnum)")

MyEnum.changeLevel(BoomLevel.Half)

print("The value of MyEnum now is: \(MyEnum)")
…la salida sería:
The name of the crane is: Crane - Backyard
The name of the crane is: Crane - Buildings

The property value of the structure is: 10
The property value of the structure is: 11

The value of MyEnum is: High
The value of MyEnum now is: Low

…problema resuelto.

Métodos de tipo

Los métodos de instancia, como se describió anteriormente, son métodos que se llaman en una instancia de un tipo particular. Pues también podemos definir métodos de tipo que es como se les llama en Switch a los métodos estáticos de toda la vida. Al igual que en otros lenguajes de programación estos se declaran escribiendo la palabra clave static antes de la palabra clave func.

Un ejemplo podría ser:

class SomeClass {

    static func someTypeMethod() {

        print("Método de tipo o método estático!!!")

    } // someTypeMethod

} // SomeClass

SomeClass.someTypeMethod()

…esto es válido tanto para las clases como para las estructuras y las enumeraciones.

Terminemos este tema con el siguiente ejemplo, donde veremos varios de los tópicos tocados en este artículo:

//: Playground - noun: a place where people can play

import UIKit

struct LevelTracker {

    static var highestUnlockedLevel = 1

    static func unlockLevel(level: Int) {

        if level > highestUnlockedLevel {

            highestUnlockedLevel = level

        } // if

    } // unlockLevel

    static func levelIsUnlocked(level: Int) -> Bool {

        return level <= highestUnlockedLevel

    } // levelIsUnlocked

    var currentLevel = 1

    mutating func advanceToLevel(level: Int) -> Bool {

        if LevelTracker.levelIsUnlocked(level) {

            currentLevel = level

            return true

        } else {

            return false

        } // else

    } // advanceToLevel

} // LevelTracker

class Player {

    var tracker = LevelTracker()

    let playerName: String

    init(name: String) {

        playerName = name

    } // init

    func completedLevel(level: Int) {

        LevelTracker.unlockLevel(level + 1)

        tracker.advanceToLevel(level + 1)

    } // completedLevel

} // Player

var player = Player(name: "Bobby")

player.completedLevel(1)

print("The highest unlocked level by player \(player.playerName) is now \(LevelTracker.highestUnlockedLevel)")

…la salida en pantalla sería:

The highest unlocked level by player Bobby is now 2

Cualquier duda con este ejemplo, dejen sus preguntas en los comentarios!

Falta aún mucho por aprender en nuestro camino a convertirnos en iOS Developer. Suscríbete a nuestra lista de correo mediante el formulario en el panel derecho y síguenos en nuestras redes sociales. Mantente así al tanto de todas nuestras publicaciones futuras.

Espero que todo cuanto se ha dicho aquí, de una forma u otra le haya servido de aprendizaje, de referencia, que haya valido su preciado tiempo.

Este artículo, al igual que el resto, será revisado con cierta frecuencia en pos de mantener un contenido de calidad y actualizado.

Cualquier sugerencia, ya sea errores a corregir, información o ejemplos a añadir será, más que bienvenida, necesaria!

Get real time updates directly on you device, subscribe now.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More

RECIBE CONTENIDO SIMILAR EN TU CORREO

RECIBE CONTENIDO SIMILAR EN TU CORREO

Suscríbete a nuestra lista de correo y mantente actualizado con las nuevas publicaciones.

Se ha suscrito correctamente!