An optional chain is a process that can request and invoke properties, methods, and subscripts, and the target for a request or call may be nil .
The optional chain returns two values:
If the target has a value, the call succeeds and returns the value
If the target is
nilthe call will returnnil
Multiple requests or calls can be linked into a chain if any node is An optional chain can be defined by placing a question mark (?) after the optional value of a property, method, or subscript. Optional chain’?’ Exclamation point (!) forces the expansion of methods, attributes, and optional chains of subscript scripts ? Call methods, properties, and subscript scripts after placing optional values ! Methods, properties, and subscript scripts are called after placing the optional value to force the expansion of the value Output more friendly error messages when optional as nil Force expand execution error when nil is optional The output of the above program execution is as follows: Want to use the exclamation point (!) to force parsing to get this person The output of the above program execution is as follows: Because of this attempt to get It is important to note that even if You can use optional chains to call properties, methods, and subscript scripts at multiple levels. This allows you to take advantage of the complexmodel between them to obtain lower-level properties and check whether such underlying properties can be successfully obtained. Four model classes are defined, including multi-layer optional chains: You can use the optional chain to call the method of the optional value and check whether the method call is successful. Even if this method does not return a value, you can still use an optional chain to achieve this. The output of the above program execution is as follows: Use the if statement to check whether the call can be successfully called You can use the optional chain to try to get a value from the subscript script and check whether the call to the subscript script is successful. However, you cannot set the subscript script through the optional chain. The output of the above program execution is as follows: The question mark of the optional chain in the subscript call comes directlyafter the john.residence and before the subscript parentheses, because john.residence is the optional value that the optional chain is trying to get. Instance to create a The output of the above program execution is as follows: Through the optional link call, we can use the subscript to read or write the optional value and determine whether the subscript call is successful ornot. The output of the above program execution is as follows: If the subscript returns a nullable type value, such as in Swift In the above example, a This example uses an optional link call to set the first element in the “Dave” array to 91, the first element in the “Bev” array + 1, and then tries to set the first element in the “Brian” array to 72. The first two calls are successful because these two key exist. But the key “Brian” does not exist in the dictionary, so the third call fails. You can connect multiple layers of optional chains together, and you can digup property methods and subscript scripts at a lower level in the model. However, the multi-layer optional chain cannot add more layers than the optional values that have been returned. If you try to get it through the optional chain The following example attempts to get the The output of the above program execution is as follows: If you work for The output result of the above example is: We can also call methods that return nullable values through optional links,and we can continue to link optional values. The output of the above program execution is as follows: nil will cause the whole chain to fail. 9.39.1. Optional chain can replace forced parsing #
9.39.2. Use the exclamation point (!) Optional chain instance #
class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() //Will cause runtime errors let roomCount = john.residence!.numberOfRooms fatal error: unexpectedly found nil while unwrapping an Optional value
residence attribute numberOfRooms property value, a run-time error will be raised because there is no residence value. 9.39.3. Use the question mark (?) Optional chain instance #
class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() // Link optional residence? Property, if residence exists, retrieve the value of numberOfRooms if let roomCount = john.residence?.numberOfRooms { print("John's room number is \(roomCount)。") } else { print("Unable to view room number") } Unable to view room number
numberOfRooms may fail, and the optionalchain will return Int? type value, or “optional Int”. When residence when empty (example above), select Int will be empty, so it will be inaccessible numberOfRooms the situation. numberOfRooms yes or no option Int(Int?) . This is also true. As long as the request through the optionalchain means that in the end numberOfRooms always return a Int? instead of Int . 9.39.4. Define a model class for an optional chain #
9.39.5. Example #
class Person { var residence: Residence? } // Defined a variable rooms, which is initialized as an empty array of type Room [] class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { return rooms[i] } func printNumberOfRooms() { print("Room number is \(numberOfRooms)") } var address: Address? } // Room Define a name attribute and an initializer for setting the room name class Room { let name: String init(name: String) { self.name = name } } // The final class in the model is called 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 } } } 9.39.6. Call a method through an optional chain #
class Person { var residence: Residence? } // Defined a variable rooms, which is initialized as an empty array of type Room [] class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { return rooms[i] } func printNumberOfRooms() { print("Room number is \(numberOfRooms)") } var address: Address? } // Room defines a name attribute and an initializer that sets the room name class Room { let name: String init(name: String) { self.name = name } } // The final class in the model is called 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("Output room number") } else { print("Unable to output room number") } Unable to output room number
printNumberOfRooms method: if the method is successfully called through the optional chain printNumberOfRooms the implicit return value of willbe Void if it is not successful, it returns nil . 9.39.7. Invoke the subscript script using the optional chain #
9.39.8. Example 1 #
class Person { var residence: Residence? } // Defined a variable rooms, which is initialized as an empty array of type Room [] class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { return rooms[i] } func printNumberOfRooms() { print("Room number is\(numberOfRooms)") } var address: Address? } // Room defines a name attribute and an initializer that sets the room name class Room { let name: String init(name: String) { self.name = name } } // The final class in the model is called 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("First room name \(firstRoomName).") } else { print("Unable to retrieve room") } Unable to retrieve room
9.39.9. Example 2 #
Residence give an example to john.residence and in his rooms . There are one or more objects in the array Room instance, then you can use the optional chain to pass the Residence thesubscript script is obtained in the rooms the instance in the array:class Person { var residence: Residence? } // Defined a variable rooms, which is initialized as an empty array of type Room [] class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { return rooms[i] } func printNumberOfRooms() { print("Room number is \(numberOfRooms)") } var address: Address? } // Room defines a name attribute and an initializer that sets the room name class Room { let name: String init(name: String) { self.name = name } } // The final class in the model is called 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: "living room")) johnsHouse.rooms.append(Room(name: "kitchen")) 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's street is \(johnsStreet)。") } else { print("Unable to retrieve address. ") } John's street is Laurel Street。
9.39.10. Access the subscript through an optional link call #
9.39.11. Example #
class Person { var residence: Residence? } // Defined a variable rooms, which is initialized as an empty array of type Room [] class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { return rooms[i] } func printNumberOfRooms() { print("Room number is \(numberOfRooms)") } var address: Address? } // Room defines a name attribute and an initializer that sets the room name class Room { let name: String init(name: String) { self.name = name } } // The final class in the model is called 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: "living room")) johnsHouse.rooms.append(Room(name: "kitchen")) john.residence = johnsHouse if let firstRoomName = john.residence?[0].name { print("The first room is named\(firstRoomName)") } else { print("Unable to retrieve room") } The first room is called the living room
9.39.12. Access the subscript of the optional type #
Dictionary of key subscript. You can put a question mark after the closing parentheses of the subscript to link the nullable return value of the subscript: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]
testScores array, which contains two key-value pairs, set the String of type key maps to an array of integers. 9.39.13. Connect multi-layer links #
Int value, no matter how many layers of links are used, the Int? . Similarly, if you try to get through the optional chain Int? value, no matter how many layers oflinks are used, the Int? . 9.39.14. Example 1 #
john of residence in theattribute address of street property. Two layers of optional chains are used to contact. residence and address property, both of which are optional typesclass Person { var residence: Residence? } // Defined a variable rooms, which is initialized as an empty array of type Room [] class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { return rooms[i] } func printNumberOfRooms() { print("Room number is \(numberOfRooms)") } var address: Address? } // Room defines a name attribute and an initializer that sets the room name class Room { let name: String init(name: String) { self.name = name } } // The final class in the model is called 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's address is \(johnsStreet).") } else { print("Unable to retrieve address") } Unable to retrieve address
9.39.15. Example 2 #
Address set an instance to act as john.residence.address and the value of address of street property sets an actual value, which you can get through a multi-layer optional chain.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("Room number is \(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: "bathroom") let johnsHouse = Residence() johnsHouse.rooms.append(Room(name: "living room")) johnsHouse.rooms.append(Room(name: "kitchen")) john.residence = johnsHouse if let firstRoomName = john.residence?[0].name { print("The first room is \(firstRoomName)") } else { print("Unable to retrieve room") } The first room is the living room
9.39.16. Link functions that return optional values #
9.39.17. Example #
class Person { var residence: Residence? } // Defined a variable rooms, which is initialized as an empty array of type Room [] class Residence { var rooms = [Room]() var numberOfRooms: Int { return rooms.count } subscript(i: Int) -> Room { return rooms[i] } func printNumberOfRooms() { print("Room number is \(numberOfRooms)") } var address: Address? } // Room defines a name attribute and an initializer that sets the room name class Room { let name: String init(name: String) { self.name = name } } // The final class in the model is called 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("Room number specified)") } else { print("No room specified room number") } No room specified room number