Swift Optional Chaining
Optional Chaining ist ein Prozess zum Abfragen und Aufrufen von Eigenschaften, Methoden und Subscripts. Das Ziel der Abfrage oder des Aufrufs kann nil sein.
Optionales Verketten gibt zwei Werte zurück:
Wenn das Ziel einen Wert hat, ist der Aufruf erfolgreich und gibt diesen Wert zurück
Wenn das Ziel nil ist, gibt der Aufruf nil zurück
Mehrere Anfragen oder Aufrufe können zu einer Kette verkettet werden; wenn ein beliebiger Knoten nil ist, schlägt die gesamte Kette fehl.
Optionales Verketten kann erzwungenes Entpacken ersetzen
Indem Sie ein Fragezeichen (?) nach dem optionalen Wert einer Eigenschaft, einer Methode oder eines Subscripts platzieren, können Sie eine optionale Kette definieren.
| Optionales Verketten '?' | Ausrufezeichen (!) erzwingt das Entpacken von optionalen Ketten für Methoden, Eigenschaften und Subscripts |
| ? wird nach einem optionalen Wert platziert, um Methoden, Eigenschaften und Subscripts aufzurufen | ! wird nach einem optionalen Wert platziert, um Methoden, Eigenschaften und Subscripts aufzurufen und den Wert zwangsweise zu entpacken |
| Wenn das Optional nil ist, wird eine freundlichere Fehlermeldung ausgegeben | Wenn das Optional nil ist, löst erzwungenes Entpacken einen Ausführungsfehler aus |
Beispiel für optionale Verkettung mit Ausrufezeichen (!)
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
//将导致运行时错误
let roomCount = john.residence!.numberOfRooms
Die Ausgabe des obigen Programms ist:
fatal error: unexpectedly found nil while unwrapping an Optional value
Der Versuch, das Ausrufezeichen (!) zum Force-Unwrap zu verwenden und den Wert der Eigenschaft numberOfRooms der residence-Eigenschaft dieser Person abzurufen, führt zu einem Laufzeitfehler, da zu diesem Zeitpunkt kein residence-Wert zum Entpacken verfügbar ist.
Beispiel für optionale Verkettung mit Fragezeichen (?)
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
// 链接可选residence?属性,如果residence存在则取回numberOfRooms的值
if let roomCount = john.residence?.numberOfRooms {
print("John 的房间号为 \(roomCount)。")
} else {
print("不能查看房间号")
}
Die Ausgabe des obigen Programms ist:
Cannot view room number
Da dieser Versuch, numberOfRooms abzurufen, fehlschlagen kann, gibt die optionale Verkettung einen Wert vom Typ Int? zurück, auch "optionales Int" genannt. Wenn residence leer ist (wie im obigen Beispiel), ist das optionale Int nil, sodass nicht auf numberOfRooms zugegriffen werden kann.
Es sollte beachtet werden, dass dies auch gilt, wenn numberOfRooms ein nicht optionales Int (Int?) ist. Solange die Anforderung über optionale Verkettung erfolgt, bedeutet dies, dass numberOfRooms immer ein Int? statt eines Int zurückgibt.
Modellklassen für optionale Verkettung definieren
Sie können optionale Verkettung verwenden, um Eigenschaften, Methoden und Subscripts über mehrere Ebenen hinweg aufzurufen. Dadurch können Sie die komplexen Modelle zwischen ihnen nutzen, um auf tiefer liegende Eigenschaften zuzugreifen und zu prüfen, ob erfolgreich auf solche tiefer liegenden Eigenschaften zugegriffen werden kann.
Beispiel
Es werden vier Modellklassen definiert, einschließlich mehrstufiger optionaler Verkettung:
class Person {
var residence: Residence?
}
// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
// Room 定义一个name属性和一个设定room名的初始化器
class Room {
let name: String
init(name: String) { self.name = name }
}
// 模型中的最终类叫做Address
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
Aufrufen von Methoden durch optionale Verkettung
Sie können optionale Verkettung verwenden, um eine Methode für einen optionalen Wert aufzurufen und zu prüfen, ob der Methodenaufruf erfolgreich ist. Selbst wenn die Methode keinen Wert zurückgibt, können Sie dennoch optionale Verkettung verwenden, um dies zu erreichen.
class Person {
var residence: Residence?
}
// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
// Room 定义一个name属性和一个设定room名的初始化器
class Room {
let name: String
init(name: String) { self.name = name }
}
// 模型中的最终类叫做Address
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
let john = Person()
if ((john.residence?.printNumberOfRooms()) != nil) {
print("输出房间号")
} else {
print("无法输出房间号")
}
Die Ausgabe des obigen Programms ist:
Unable to output room number
Verwenden Sie eine if-Anweisung, um zu prüfen, ob die Methode printNumberOfRooms erfolgreich aufgerufen werden kann: Wenn der Methodenaufruf über optionale Verkettung erfolgreich ist, ist der implizite Rückgabewert von printNumberOfRooms Void; wenn er nicht erfolgreich ist, gibt er nil zurück.
Optionale Verkettung zum Aufrufen von Subscripts verwenden
Du kannst optionale Verkettung verwenden, um zu versuchen, einen Wert aus einem Subscript abzurufen, und zu prüfen, ob der Subscript-Aufruf erfolgreich ist; du kannst jedoch kein Subscript durch optionale Verkettung setzen.
Beispiel 1
class Person {
var residence: Residence?
}
// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
// Room 定义一个name属性和一个设定room名的初始化器
class Room {
let name: String
init(name: String) { self.name = name }
}
// 模型中的最终类叫做Address
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
let john = Person()
if let firstRoomName = john.residence?[0].name {
print("第一个房间名 \(firstRoomName).")
} else {
print("无法检索到房间")
}
Die Ausgabe des obigen Programms ist:
Unable to retrieve the room
Beim Subscript-Aufruf steht das Fragezeichen der optionalen Verkettung direkt nach john.residence und vor den Subscript-Klammern, weil john.residence der optionale Wert ist, den die optionale Verkettung abzurufen versucht.
Beispiel 2
Im Beispiel wird eine Residence-Instanz für john.residence erstellt, und in seinem rooms-Array befinden sich eine oder mehrere Room-Instanzen. Dann kannst du optionale Verkettung verwenden, um die Instanzen im rooms-Array über das Residence-Subscript abzurufen:
class Person {
var residence: Residence?
}
// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
// Room 定义一个name属性和一个设定room名的初始化器
class Room {
let name: String
init(name: String) { self.name = name }
}
// 模型中的最终类叫做Address
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
let john = Person()
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse
let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
john.residence!.address = johnsAddress
if let johnsStreet = john.residence?.address?.street {
print("John 所在的街道是 \(johnsStreet)。")
} else {
print("无法检索到地址。 ")
}
Die Ausgabe des obigen Programms ist:
John 所在的街道是 Laurel Street.
Zugriff auf Subscripts über Aufrufe optionaler Verkettung
Durch Aufrufe optionaler Verkettung können wir Subscripts verwenden, um einen optionalen Wert zu lesen oder zu schreiben, und feststellen, ob der Subscript-Aufruf erfolgreich ist.
Beispiel
class Person {
var residence: Residence?
}
// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
// Room 定义一个name属性和一个设定room名的初始化器
class Room {
let name: String
init(name: String) { self.name = name }
}
// 模型中的最终类叫做Address
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
let john = Person()
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse
if let firstRoomName = john.residence?[0].name {
print("第一个房间名为\(firstRoomName)")
} else {
print("无法检索到房间")
}
Die Ausgabe des obigen Programms ist:
The first room is named living room
Zugriff auf Subscripts eines optionalen Typs
Wenn ein Subscript einen Wert eines optionalen Typs zurückgibt, wie etwa das Schlüssel-Subscript von Dictionary in Swift, kannst du ein Fragezeichen nach der schließenden Klammer des Subscripts platzieren, um an den optionalen Rückgabewert des Subscripts zu verketten:
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]] testScores["Dave"]?[0] = 91 testScores["Bev"]?[0]++ testScores["Brian"]?[0] = 72 // the "Dave" array is now [91, 82, 84] and the "Bev" array is now [80, 94, 81]
Im obigen Beispiel wird ein testScores-Array definiert, das zwei Schlüssel-Wert-Paare enthält und Schlüssel vom Typ String auf ein Integer-Array abbildet.
Dieses Beispiel verwendet Aufrufe optionaler Verkettung, um das erste Element des "Dave"-Arrays auf 91 zu setzen, das erste Element des "Bev"-Arrays um 1 zu erhöhen und dann zu versuchen, das erste Element des "Brian"-Arrays auf 72 zu setzen.
Die ersten beiden Aufrufe sind erfolgreich, weil diese beiden Schlüssel existieren. Aber der Schlüssel "Brian" existiert nicht im Dictionary, also schlägt der dritte Aufruf fehl.
Mehrere Ebenen der Verkettung verbinden
Du kannst mehrere Ebenen optionaler Verkettung miteinander verbinden, um Eigenschaften, Methoden und Subscripts weiter unten in einem Modell zu erreichen. Allerdings kann mehrstufige optionale Verkettung nicht mehr Ebenen hinzufügen als der bereits zurückgegebene optionale Wert.
Wenn Sie versuchen, einen Int-Wert durch optionale Verkettung zu erhalten, ist die Rückgabe unabhängig von der Anzahl der verwendeten Verkettungsebenen immer Int?. Wenn Sie entsprechend versuchen, einen Int?-Wert durch optionale Verkettung zu erhalten, ist die Rückgabe unabhängig von der Anzahl der verwendeten Verkettungsebenen immer Int?.
Beispiel 1
Das folgende Beispiel versucht, die street-Eigenschaft der address in johns residence-Eigenschaft abzurufen. Hier werden zwei Ebenen der optionalen Verkettung verwendet, um die Eigenschaften residence und address zu verknüpfen, die beide optionale Typen sind:
class Person {
var residence: Residence?
}
// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
// Room 定义一个name属性和一个设定room名的初始化器
class Room {
let name: String
init(name: String) { self.name = name }
}
// 模型中的最终类叫做Address
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
let john = Person()
if let johnsStreet = john.residence?.address?.street {
print("John 的地址为 \(johnsStreet).")
} else {
print("不能检索地址")
}
Die Ausgabe des obigen Programms ist:
Unable to retrieve address
Beispiel 2
Wenn Sie eine Instanz von Address als Wert von john.residence.address festlegen und einen tatsächlichen Wert für die street-Eigenschaft von address festlegen, können Sie diesen Eigenschaftswert durch mehrstufige optionale Verkettung erhalten.
class Person {
var residence: Residence?
}
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
get{
return rooms[i]
}
set {
rooms[i] = newValue
}
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
class Room {
let name: String
init(name: String) { self.name = name }
}
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
let john = Person()
john.residence?[0] = Room(name: "浴室")
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse
if let firstRoomName = john.residence?[0].name {
print("第一个房间是\(firstRoomName)")
} else {
print("无法检索房间")
}
Die Ausgabe des obigen Beispiels ist:
The first room is the living room
Verkettung von Funktionen, die optionale Werte zurückgeben
Wir können auch optionale Verkettung verwenden, um Methoden aufzurufen, die optionale Werte zurückgeben, und können auf dem optionalen Wert weiter verketten.
Beispiel
class Person {
var residence: Residence?
}
// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("房间号为 \(numberOfRooms)")
}
var address: Address?
}
// Room 定义一个name属性和一个设定room名的初始化器
class Room {
let name: String
init(name: String) { self.name = name }
}
// 模型中的最终类叫做Address
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
let john = Person()
if john.residence?.printNumberOfRooms() != nil {
print("指定了房间号)")
} else {
print("未指定房间号")
}
Die Ausgabe des obigen Programms ist:
No room number specifiedAndere Erweiterungen