Swift - Chaînage en option
Le processus d'interrogation, d'appel de propriétés, d'indices et de méthodes sur une option qui peut être «nil» est défini comme un chaînage facultatif. Le chaînage facultatif renvoie deux valeurs -
si l'option contient une 'valeur', l'appel de sa propriété, de ses méthodes et de ses indices associés renvoie des valeurs
si l'option contient une valeur 'nil', toutes ses propriétés, méthodes et indices associés retournent nil
Étant donné que plusieurs requêtes aux méthodes, propriétés et indices sont regroupées, l'échec d'une chaîne affectera toute la chaîne et se traduira par une valeur «nil».
Chaînage facultatif comme alternative au déballage forcé
Le chaînage facultatif est spécifié après la valeur facultative avec '?' pour appeler une propriété, une méthode ou un indice lorsque la valeur facultative renvoie des valeurs.
Chaînage facultatif '?' | Accès aux méthodes, propriétés et indices Chaining optionnel '!' pour forcer le déballage |
? est placé après la valeur facultative pour appeler la propriété, la méthode ou l'indice | ! est placé après la valeur facultative pour appeler la propriété, la méthode ou l'indice pour forcer le déroulement de la valeur |
Échoue gracieusement lorsque l'option est «nil» | Le déballage forcé déclenche une erreur d'exécution lorsque l'option est «nil» |
Programme de chaînage optionnel avec '!'
class ElectionPoll {
var candidate: Pollbooth?
}
lass Pollbooth {
var name = "MP"
}
let cand = ElectionPoll()
let candname = cand.candidate!.name
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
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
Le programme ci-dessus déclare «scrutin d'élection» comme nom de classe et contient «candidat» comme fonction d'appartenance. La sous-classe est déclarée comme «cabine de vote» et «nom» comme sa fonction d'appartenance qui est initialisée comme «MP». L'appel à la super classe est initialisé en créant une instance «cand» avec facultatif «!». Étant donné que les valeurs ne sont pas déclarées dans sa classe de base, la valeur «nil» est stockée, renvoyant ainsi une erreur fatale par la procédure de déballage forcé.
Programme de chaînage optionnel avec '?'
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")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Candidate name cannot be retreived
Le programme ci-dessus déclare «scrutin d'élection» comme nom de classe et contient «candidat» comme fonction d'appartenance. La sous-classe est déclarée comme «cabine de vote» et «nom» comme sa fonction d'appartenance qui est initialisée comme «MP». L'appel à la super classe est initialisé en créant une instance «cand» avec facultatif «?». Puisque les valeurs ne sont pas déclarées dans sa classe de base, la valeur «nil» est stockée et imprimée dans la console par le bloc de gestionnaire else.
Définition de classes de modèle pour le chaînage facultatif et l'accès aux propriétés
Le langage Swift 4 fournit également le concept de chaînage facultatif, pour déclarer plus d'une sous-classe en tant que classes de modèle. Ce concept sera très utile pour définir des modèles complexes et accéder aux propriétés, méthodes et sous-propriétés des sous-propriétés.
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")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Rectangle Area is not specified
Appel de méthodes via un chaînage facultatif
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")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Area of circle is not specified
La fonction circleprint () déclarée dans la sous-classe circle () est appelée en créant une instance nommée 'circname'. La fonction retournera une valeur si elle contient une valeur, sinon elle retournera un message d'impression défini par l'utilisateur en vérifiant l'instruction 'if circname.print? .Circleprint ()! = Nil'.
Accès aux abonnements via le chaînage facultatif
Le chaînage facultatif est utilisé pour définir et récupérer une valeur d'indice pour valider si l'appel à cet indice renvoie une valeur. '?' est placé avant les accolades de l'indice pour accéder à la valeur facultative de l'indice particulier.
Programme 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.")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Radius is not specified.
Dans le programme ci-dessus, les valeurs d'instance pour la fonction d'appartenance 'radiusName' ne sont pas spécifiées. Par conséquent, l'appel du programme à la fonction ne retournera que d'autre part alors que pour renvoyer les valeurs, nous devons définir les valeurs de la fonction d'appartenance particulière.
Programme 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.")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Radius is measured in Units.
Dans le programme ci-dessus, les valeurs d'instance de la fonction d'appartenance 'radiusName' sont spécifiées. Par conséquent, l'appel du programme à la fonction renverra désormais des valeurs.
Accès aux indices de type facultatif
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])
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Optional(35)
Optional(78)
Optional(78)
Optional(101)
Optional(90)
Optional(44)
Optional(56)
Les valeurs facultatives des indices sont accessibles en se référant à leurs valeurs d'indice. Il est accessible en indice [0], indice [1] etc. Les valeurs d'indice par défaut pour 'rayon' sont d'abord attribuées comme [35, 45, 78, 101] et pour 'Circle' [90, 45, 56]] . Ensuite, les valeurs de l'indice sont modifiées en tant que Rayon [0] à 78 et Cercle [1] à 45.
Lier plusieurs niveaux de chaînage
Plusieurs sous-classes peuvent également être liées à ses méthodes, propriétés et indices de super classe par chaînage facultatif.
Le chaînage multiple des options peut être lié -
Si la récupération du type n'est pas facultative, le chaînage facultatif renverra une valeur facultative. Par exemple, si String via le chaînage facultatif, il retournera String? Valeur
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.")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Radius is not specified.
Dans le programme ci-dessus, les valeurs d'instance de la fonction d'appartenance 'radiusName' ne sont pas spécifiées. Par conséquent, l'appel du programme à la fonction ne retournera qu'une partie du reste alors que pour renvoyer les valeurs, nous devons définir les valeurs de la fonction d'appartenance particulière.
Si le type de récupération est déjà facultatif, le chaînage facultatif renverra également une valeur facultative. Par exemple, si String? Est-ce accessible via un chaînage facultatif, il retournera String? Valeur..
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.")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Radius is measured in Units.
Dans le programme ci-dessus, les valeurs d'instance de la fonction d'appartenance 'radiusName' sont spécifiées. Par conséquent, l'appel de programme à la fonction renverra désormais des valeurs.
Chaînage sur des méthodes avec des valeurs de retour facultatives
Le chaînage facultatif est également utilisé pour accéder aux méthodes définies par les sous-classes.
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")
}
Lorsque nous exécutons le programme ci-dessus en utilisant aire de jeux, nous obtenons le résultat suivant -
Area of circle is not specified