Swift - Extensiones

La funcionalidad de una clase, estructura o tipo de enumeración existente se puede agregar con la ayuda de extensiones. La funcionalidad de tipo se puede agregar con extensiones, pero no es posible anular la funcionalidad con las extensiones.

Swift Extension Functionalities -

  • Agregar propiedades calculadas y propiedades de tipo calculadas
  • Definición de métodos de instancia y tipo.
  • Proporcionar nuevos inicializadores.
  • Definición de subíndices
  • Definición y uso de nuevos tipos anidados
  • Hacer que un tipo existente se ajuste a un protocolo

Las extensiones se declaran con la palabra clave 'extensión'

Sintaxis

extension SomeType {
   // new functionality can be added here
}

El tipo existente también se puede agregar con extensiones para convertirlo en un protocolo estándar y su sintaxis es similar a la de las clases o estructuras.

extension SomeType: SomeProtocol, AnotherProtocol {
   // protocol requirements is described here
}

Propiedades calculadas

Las propiedades de 'instancia' y 'tipo' calculadas también se pueden ampliar con la ayuda de extensiones.

extension Int {
   var add: Int {return self + 100 }
   var sub: Int { return self - 10 }
   var mul: Int { return self * 10 }
   var div: Int { return self / 5 }
}

let addition = 3.add
print("Addition is \(addition)")

let subtraction = 120.sub
print("Subtraction is \(subtraction)")

let multiplication = 39.mul
print("Multiplication is \(multiplication)")

let division = 55.div
print("Division is \(division)")

let mix = 30.add + 34.sub
print("Mixed Type is \(mix)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Addition is 103
Subtraction is 110
Multiplication is 390
Division is 11
Mixed Type is 154

Inicializadores

Swift 4 proporciona la flexibilidad de agregar nuevos inicializadores a un tipo existente mediante extensiones. El usuario puede agregar sus propios tipos personalizados para ampliar los tipos ya definidos y también son posibles opciones de inicialización adicionales. Las extensiones solo admiten init (). deinit () no es compatible con las extensiones.

struct sum {
   var num1 = 100, num2 = 200
}

struct diff {
   var no1 = 200, no2 = 100
}

struct mult {
   var a = sum()
   var b = diff()
}

let calc = mult()
print ("Inside mult block \(calc.a.num1, calc.a.num2)")
print("Inside mult block \(calc.b.no1, calc.b.no2)")

let memcalc = mult(a: sum(num1: 300, num2: 500),b: diff(no1: 300, no2: 100))
print("Inside mult block \(memcalc.a.num1, memcalc.a.num2)")
print("Inside mult block \(memcalc.b.no1, memcalc.b.no2)")

extension mult {
   init(x: sum, y: diff) {
      let X = x.num1 + x.num2
      let Y = y.no1 + y.no2
   }
}

let a = sum(num1: 100, num2: 200)
print("Inside Sum Block:\( a.num1, a.num2)")

let b = diff(no1: 200, no2: 100)
print("Inside Diff Block: \(b.no1, b.no2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Inside mult block (100, 200)
Inside mult block (200, 100)
Inside mult block (300, 500)
Inside mult block (300, 100)
Inside Sum Block:(100, 200)
Inside Diff Block: (200, 100)

Métodos

Se pueden agregar nuevos métodos de instancia y métodos de tipo a la subclase con la ayuda de extensiones.

extension Int {
   func topics(summation: () -> ()) {
      for _ in 0..<self {
         summation()
      }
   }
}

4.topics(summation: {
   print("Inside Extensions Block")
})

3.topics(summation: {
   print("Inside Type Casting Block")
})

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Inside Extensions Block
Inside Extensions Block
Inside Extensions Block
Inside Extensions Block
Inside Type Casting Block
Inside Type Casting Block
Inside Type Casting Block

La función topics () toma un argumento de tipo '(suma: () → ())' para indicar que la función no toma ningún argumento y no devolverá ningún valor. Para llamar a esa función varias veces, se inicializa el bloque for y se inicializa la llamada al método con topic ().

Métodos de instancia de mutación

Los métodos de instancia también se pueden modificar cuando se declaran como extensiones.

Los métodos de estructura y enumeración que se modifican a sí mismos o sus propiedades deben marcar el método de instancia como mutante, al igual que los métodos mutados de una implementación original.

extension Double {
   mutating func square() {
      let pi = 3.1415
      self = pi * self * self
   }
}

var Trial1 = 3.3
Trial1.square()
print("Area of circle is: \(Trial1)")

var Trial2 = 5.8
Trial2.square()
print("Area of circle is: \(Trial2)")

var Trial3 = 120.3
Trial3.square()
print("Area of circle is: \(Trial3)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Area of circle is: 34.210935
Area of circle is: 105.68006
Area of circle is: 45464.070735

Subíndices

También es posible agregar nuevos subíndices a instancias ya declaradas con extensiones.

extension Int {
   subscript(var multtable: Int) -> Int {
      var no1 = 1
      while multtable > 0 {
         no1 *= 10
         --multtable
      }
      return (self / no1) % 10
   }
}

print(12[0])
print(7869[1])
print(786543[2])

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

2
6
5

Tipos anidados

Los tipos anidados para instancias de clase, estructura y enumeración también se pueden ampliar con la ayuda de extensiones.

extension Int {
   enum calc {
      case add
      case sub
      case mult
      case div
      case anything
   }
   var print: calc {
      switch self {
         case 0:
            return .add
         case 1:
            return .sub
         case 2:
            return .mult
         case 3:
            return .div
         default:
            return .anything
      }
   }
}

func result(numb: [Int]) {
   for i in numb {
      switch i.print {
         case .add:
            print(" 10 ")
         case .sub:
            print(" 20 ")
         case .mult:
            print(" 30 ")
         case .div:
            print(" 40 ")
         default:
            print(" 50 ")
      }
   }
}
result(numb: [0, 1, 2, 3, 4, 7])

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

10
20
30
40
50
50