Swift - encadeamento opcional

O processo de consultar, chamar propriedades, subscritos e métodos em um opcional que pode ser 'nulo' é definido como encadeamento opcional. O encadeamento opcional retorna dois valores -

  • se o opcional contém um 'valor', chamar sua propriedade, métodos e subscritos relacionados retorna valores

  • se o opcional contém um valor 'nulo', todas as suas propriedades relacionadas, métodos e subscritos retornam nulo

Visto que várias consultas a métodos, propriedades e subscritos são agrupados, a falha em uma cadeia afetará toda a cadeia e resultará em valor 'nulo'.

Encadeamento opcional como alternativa ao desembrulhamento forçado

O encadeamento opcional é especificado após o valor opcional com '?' para chamar uma propriedade, método ou subscrito quando o valor opcional retorna alguns valores.

Encadeamento opcional '?' Acesso a métodos, propriedades e subscritosCadeamento opcional '!' forçar o desembrulhar
? é colocado após o valor opcional para chamar a propriedade, método ou subscrito ! é colocado após o valor opcional para chamar a propriedade, método ou subscrito para forçar o desempacotamento do valor
Falha normalmente quando o opcional é 'nulo' O desempacotamento forçado aciona um erro de tempo de execução quando o opcional é 'nulo'

Programa para encadeamento opcional com '!'

class ElectionPoll {
   var candidate: Pollbooth?
}

lass Pollbooth {
   var name = "MP"
}

let cand = ElectionPoll()
let candname = cand.candidate!.name

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

fatal error: unexpectedly found nil while unwrapping an Optional value
0 Swift 4 0x0000000103410b68
llvm::sys::PrintStackTrace(__sFILE*) + 40
1 Swift 4 0x0000000103411054 SignalHandler(int) + 452
2 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26
3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939
4 libsystem_platform.dylib 0x00000001074a0214 _sigtramp + 1976783636
5 Swift 4 0x0000000102a85c39
llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329
6 Swift 4 0x0000000102d320b3
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::__1::vector<std::__1::basic_string, std::__1::allocator >,
std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&,
char const* const*) + 1523
7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift
4::CompilerInstance&, std::__1::vector<std::__1::basic_string,
std::__1::allocator >, std::__1::allocator<std::__1::basic_string,
std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions
const&) + 1066
8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef,
char const*, void*) + 5275
9 Swift 4 0x0000000102754a6d main + 1677
10 libdyld.dylib 0x00007fff8bb9e5c9 start + 1
11 libdyld.dylib 0x000000000000000c start + 1950751300
Stack dump:
0. Program arguments:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 -
target-cpu core2 -sdk
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/
SDKs/MacOSX10.10.sdk -module-name main
/bin/sh: line 47: 15672 Done cat <<'SWIFT 4'
import Foundation
</std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std::
__1::basic_string

O programa acima declara 'pesquisa eleitoral' como nome da classe e contém 'candidato' como função de associação. A subclasse é declarada como 'poll booth' e 'nome' como sua função de associação que é inicializada como 'MP'. A chamada para a superclasse é inicializada criando uma instância 'cand' com '!' Opcional. Uma vez que os valores não são declarados em sua classe base, o valor 'nulo' é armazenado, retornando assim um erro fatal pelo procedimento de desempacotamento forçado.

Programa para encadeamento opcional com '?'

class ElectionPoll {
   var candidate: Pollbooth?
}

class Pollbooth {
   var name = "MP"
}
let cand = ElectionPoll()

if let candname = cand.candidate?.name {
   print("Candidate name is \(candname)")
} else {
   print("Candidate name cannot be retreived")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Candidate name cannot be retreived

O programa acima declara 'pesquisa eleitoral' como nome da classe e contém 'candidato' como função de associação. A subclasse é declarada como 'poll booth' e 'nome' como sua função de associação que é inicializada como 'MP'. A chamada para a superclasse é inicializada criando uma instância 'cand' com '?' Opcional. Como os valores não são declarados em sua classe base, o valor 'nil' é armazenado e impresso no console pelo bloco do manipulador else.

Definindo classes de modelo para propriedades de encadeamento e acesso opcionais

A linguagem Swift 4 também fornece o conceito de encadeamento opcional, para declarar mais de uma subclasse como classes de modelo. Este conceito será muito útil para definir modelos complexos e para acessar as propriedades, métodos e subpropriedades dos subscritos.

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var street: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let rectname = rectangle()
if let rectarea = rectname.print?.cprint {
   print("Area of rectangle is \(rectarea)")
} else {
   print("Rectangle Area is not specified")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Rectangle Area is not specified

Métodos de chamada por meio de encadeamento opcional

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }

   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Area of circle is not specified

A função circleprint () declarada dentro da subclasse circle () é chamada criando uma instância chamada 'circname'. A função retornará um valor se contiver algum valor, caso contrário, retornará alguma mensagem de impressão definida pelo usuário verificando a instrução 'if circname.print? .Circleprint ()! = Nil'.

Acessando subscritos por meio de encadeamento opcional

O encadeamento opcional é usado para definir e recuperar um valor de subscrito para validar se a chamada para esse subscrito retorna um valor. '?' é colocado antes das chaves do subscrito para acessar o valor opcional no subscrito particular.

Programa 1

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname =  radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Radius is not specified.

No programa acima, os valores de instância para a função de pertinência 'radiusName' não são especificados. Portanto, a chamada do programa para a função retornará apenas a outra parte, enquanto para retornar os valores temos que definir os valores para a função de pertinência particular.

Programa 2

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Radius is measured in Units.

No programa acima, os valores de instância para a função de pertinência 'radiusName' são especificados. Portanto, a chamada do programa para a função agora retornará valores.

Acessando Subscritos de Tipo Opcional

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }

   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")

let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]]
area["Radius"]?[1] = 78
area["Circle"]?[1]--

print(area["Radius"]?[0])
print(area["Radius"]?[1])
print(area["Radius"]?[2])
print(area["Radius"]?[3])

print(area["Circle"]?[0])
print(area["Circle"]?[1])
print(area["Circle"]?[2])

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Optional(35)
Optional(78)
Optional(78)
Optional(101)
Optional(90)
Optional(44)
Optional(56)

Os valores opcionais para subscritos podem ser acessados ​​referindo-se a seus valores subscritos. Ele pode ser acessado como subscrito [0], subscrito [1] etc. Os valores subscritos padrão para 'raio' são atribuídos primeiro como [35, 45, 78, 101] e para 'Círculo' [90, 45, 56]] . Em seguida, os valores subscritos são alterados como Raio [0] a 78 e Círculo [1] a 45.

Vinculando vários níveis de encadeamento

Múltiplas subclasses também podem ser vinculadas com seus métodos de superclasse, propriedades e subscritos por encadeamento opcional.

Encadeamento múltiplo de opcional pode ser vinculado -

Se a recuperação do tipo não for opcional, o encadeamento opcional retornará um valor opcional. Por exemplo, se String por meio de encadeamento opcional, ele retornará String? Valor

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Radius is not specified.

No programa acima, os valores de instância para a função de pertinência 'radiusName' não são especificados. Conseqüentemente, a chamada do programa para a função retornará apenas a outra parte, enquanto para retornar os valores temos que definir os valores para a função de pertinência específica.

Se o tipo de recuperação já for opcional, o encadeamento opcional também retornará um valor opcional. Por exemplo, se String? Se for acessado por meio de encadeamento opcional, ele retornará String? Valor..

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Radius is measured in Units.

No programa acima, os valores de instância para a função de associação 'radiusName' são especificados. Portanto, a chamada do programa para a função agora retornará valores.

Encadeamento de métodos com valores de retorno opcionais

O encadeamento opcional também é usado para acessar métodos definidos de subclasses.

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Quando executamos o programa acima usando playground, obtemos o seguinte resultado -

Area of circle is not specified