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