An attack on the swift-------------an empty chain call

Source: Internet
Author: User
Tags access properties



Details turn from: http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html



A nullable chained invocation (Optional Chaining) is a procedure that can request and invoke properties, methods, and subscripts, and its nullability is reflected in the possibility that the target of a request or call may currently be empty (nil). If the nullable target has a value, the call succeeds, and if the selected target is null (nil), the call returns Null (NIL). Multiple successive calls can be chained together to form a call chain, and if any one of the nodes is empty (nil) will cause the entire chain call to fail.


Note: Swift's nullable chaining calls and messages in Objective-c are somewhat similar, but Swift can be used in any type and be able to check whether the call was successful.




Use a nullable chained tone to force the expansion


You can define a nullable chain by placing a question mark after you want to invoke a non-empty property, method, or nullable value (optional value) of the subscript. This is much like placing an exclamation mark after a nullable value (! ) to force the expansion of the value. The main difference between them is that when a nullable value is empty, a nullable chain is simply a call failure, but forcing the expansion will trigger a run-time error.



To reflect that a nullable chain call can be called on an empty object (nil), the returned result is a nullable value, regardless of whether the returned value of the call's property, method, subscript, and so on is a nullable value. You can use this return value to determine whether your nullable chain call succeeds, and if the call has a return value, the call succeeds and the callnilfails.



In particular, the return result of a nullable chain call has the same type as the original return result, but is packaged as a nullable type value. When a nullable chain call succeeds, the result of a type that should be returnedIntwill return theInt?type.



The following sections of code explain the differences between nullable chained calls and forced deployment. First, two classes and a are definedPersonResidence.


 
 
class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}


ResidenceThere is aInttype of propertynumberOfRoomswhose default value is 1.Personhas a nullableresidenceproperty whose type isResidence?.



If you create a newPersoninstance because itsresidenceproperties are nullable, thejohnproperty is initialized tonil:


let john = Person()


If you use an exclamation mark (! Forcing an expansion to getjohntheresidencevalue in this propertynumberOfRoomstriggers a run-time error because there is no expandableresidence:


let roomCount = john.residence!.numberOfRooms// this triggers a runtime error


john.residenceWhen not empty, the above call succeeds androomCountsets theIntnumber of rooms to the type. As mentioned above,residencethis code will trigger a run-time error when it is empty.



A nullable chained invocation provides anothernumberOfRoomsway to access, using a question mark (? ) to replace the original exclamation mark (! ) is located in:


 
if let roomCount = john.residence?.numberOfRooms {
    print("John‘s residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// prints "Unable to retrieve the number of rooms."


residenceafter adding a question mark later, Swift will beresidenceaccessed without being emptynumberOfRooms.



Because Access cannumberOfRoomsfail, a nullable chain call returns aInt?type, or "nullable int". As shown in the example above, when done, the nullableresidencenilwill beIntnil, indicating that no access is possiblenumberOfRooms.



It is important to note thatnumberOfRoomsthis is true even when it is not availableInt. As long as it is called through a nullable chain, it means that the lastnumberOfRoomsone is returned insteadInt?ofInt.



By assigningjohn.residenceanResidenceinstance variable to one:


john.residence = Residence()


This isjohn.residencenotnilthe case. Normal access is now availablejohn.residence.numberOfRooms, with a value of default of 1 and a type ofInt?:


 
if let roomCount = john.residence?.numberOfRooms {
    print("John‘s residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// prints "John‘s residence has 1 room(s)."




To define a model class for a nullable chained call


Multi-layered properties, methods, and subscripts can be called by using a nullable chain call. This allows the various sub-properties to be accessed down through various models. and determine whether you can access properties, methods, or subscripts of child properties.



The following code defines four model classes, including multi-layer nullable chain calls. In order to facilitate the description, onPersonand onResidencethe basis of addedRoomandAddress, as well as related attributes, methods and subscripts.



The person class definition basically remains the same:


class Person { var residence: Residence?}


ResidenceThe analogy is more complex and adds anRoomempty array of typeroom:


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("The number of rooms is \(numberOfRooms)")
    }
    var address: Address?
}


Now thatResidenceyou have anRoomarray of storage types, thenumberOfRoomsattributes need to be computed, not as simple variables. The computednumberOfRoomsproperty value of the returnedroomsarraycount. NowResidencealso provides access toroomsan array of shortcuts to access the array elements at the specified location through a read-write subscript. In addition, the methodprintNumberOfRoomsis provided, the function of which is to output the number of rooms in this House. Finally,Residencea nullable property is definedaddress, which is of typeAddress?.Addressthe definition of the class is described below.



A classRoomis a simple class that contains only one propertyname, and an initialization function:


class Room { let name: String init(name: String) { self.name = name }}


The last class isAddress, and this class has threestrings?The Nullable property of the type. Thebuildingnameandbuildingnumberproperties represent the name and number of the building used to represent a particular building. The third property represents the name of the street where the building is located:


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
        }
    }
}


ClassAddressprovides abuildingIdentifier()method that returns a value ofString?. Returns if notbuildingNameempty, orbuildingNamereturns ifbuildingNumbernot emptybuildingNumber. Returns if both properties are emptynil.





Accessing properties via a nullable chained call


As described in forcing the deployment using a nullable chained call, you can access the nullable value of the property through a nullable chained invocation and determine whether the access was successful.



The following code creates anPersoninstance and then accesses thenumberOfRoomsproperties:


 
let john = Person()
if let roomCount = john.residence?.numberOfRooms {
    print("John‘s residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// prints "Unable to retrieve the number of rooms."


Becausejohn.residenceofnilthat, there is no doubt that this nullable chain call failed.



To set the property value by a nullable chain call:


 
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress


In this case, itjohn.residenceis not possible to set aaddressproperty, becausejohn.residencenil.





Calling a method with a nullable chain call


The method can be invoked through a nullable chained call, and determines whether the call succeeds, even if the method does not return a value.Residencethe method in theprintNumberOfRooms()output currentnumberOfRoomsvalue:


func printNumberOfRooms() { print("The number of rooms is \(numberOfRooms)")}


This method has no return value. However, methods that do not return a value implicitly return aVoidtype, as described in the no return value function. This means that a method that does not return a value also returns () or an empty tuple.



If the method is called by a nullable chained call on a nullable value, the return type of the method isVoid?, notVoid, because the return value obtained through a nullable chain call is nullable. This allows us to useifstatements to determine whether a method can be successfully calledprintNumberOfRooms(), even if the method itself does not have a return value defined. Whether the call succeeds by returning the valuenil:


 
if john.residence?.printNumberOfRooms() != nil {
    print("It was possible to print the number of rooms.")
} else {
    print("It was not possible to print the number of rooms.")
}
// prints "It was not possible to print the number of rooms."


Similarly, it is possible to determine whether a value is successfully assigned to a property through a nullable chain call. In the example above, we try tojohn.residenceassign a value to aaddressproperty in, even ifresidencenil. Assigning a value to an attribute via a nullable chain call is returnedVoid?by judging whether the return value isnilknown to be successful:


if (john.residence?.address = someAddress) != nil {
    print("It was possible to set the address.")
} else {
    print("It was not possible to set the address.")
}
// prints "It was not possible to set the address."




Access subscript via a nullable chain transfer


With a nullable chain call, we can use subscripts to read or write to nullable values, and to determine if the subscript call was successful.


Note: When you access the subscript of a nullable value through a nullable chain call, you should place the question mark in front of the subscript square brackets instead of behind. A question mark that can be called with an empty chain is usually followed directly by a nullable expression.


The following example uses subscript to access the name of thejohn.residenceroomsfirst room in the array,john.residencebecausenil, therefore, the subscript call fails without a doubt:


 
if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
} else {
    print("Unable to retrieve the first room name.")
}
// prints "Unable to retrieve the first room name."


In this example, the question mark is placed directlyjohn.residencebehind the square brackets, becausejohn.residenceit is a nullable value.



Similarly, the subscript can be used to assign a value by using the nullable chain-type adjustment:


john.residence?[0] = Room(name: "Bathroom")


This assignment will also fail, asresidenceit is nownil.



If you create anResidenceinstance, add someRoominstances and assign valuesjohn.residence, you can access the elements in the array through an optional chain and subscript:


 
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 name is \(firstRoomName).")
} else {
    print("Unable to retrieve the first room name.")
}
// prints "The first room name is Living Room."




To access the subscript of a nullable type


If the subscript returns a nullable type value, such as a subscript in SwiftDictionarykey. You can link the nullable return value of the subscript by placing a question mark after the closing parenthesis 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]


In the example above, antestScoresarray is defined, containing two key-value pairs, whichStringmap the typekeyto an array of shaping. This example uses a nullable chain call to set the first element in the "Dave" array to 91, the first element of the "Bev" array to +1, and then attempts to set the first element in the "Brian" array to 72. The first two calls are successful because these twokeyexist. But the key "Brian" does not exist in the dictionary, so the third call fails.





Multi-layer Links


You can access properties, methods, and subscripts down through multiple links with several nullable chaining. However, the nullability of the return value is not added to the multi-layer nullable chain call.



Other words:


    • If the value you are accessing is not nullable, the nullable chain call will put back a nullable value.
    • If the value you are accessing is already nullable, the call through a nullable chain will not become "more" nullable.


So:


    • Accessing a value through a nullable chain callIntwill returnInt?, but how many times can a nullable chain call be made.
    • Similarly, access to a value through a nullable chain callInt?does not become more nullable.


The following example accesses the properties in thejohnresidenceaddressstreet. This uses a two-layer nullable chain call, and both are nullableresidenceaddressvalues.


 
if let johnsStreet = john.residence?.address?.street { print("John‘s street name is \(johnsStreet).")
} else { print("Unable to retrieve the address.")
} // prints "Unable to retrieve the address."


john.residenceContainsResidencean instance, butjohn.residence.addressis anil. Therefore, it cannot be accessedjohn.residence?.address?.street.



It is important to note that in the example above,streetthe properties areString?.john.residence?.address?.streetThe return value is also stillString?, even if two nullable chained calls have been made.



If youjohn.residence.addresspoint to an instance and assign a value to aaddressstreetproperty in, we can pass through the nullable chaining to access thestreetproperty.


 
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 name is \(johnsStreet).")
} else { print("Unable to retrieve the address.")
} // prints "John‘s street name is Laurel Street."


In the example above, thejohn.residenceResidencejohn.residenceproperty assignment succeeds because it is an available instanceaddress.





Links to functions that return nullable values


The example above shows how to get a nullable property value through a nullable chain call. We can also invoke a method that returns a nullable value through a nullable chained call, and you can continue to link to a nullable value.



In the following example, a method called by a nullable chained callAddressis usedbuildingIdentifier(). This method returns theString?type. As mentioned above, the final return value of a method through a nullable chain call isString?:


 
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() { print("John‘s building identifier is \(buildingIdentifier).")
} // prints "John‘s building identifier is The Larches."


If you want to further make a nullable chained call to the return value of a method,buildingIdentifier()add a question mark after the method's parentheses:


 
if let beginsWithThe =
    john.residence?.address?.buildingIdentifier()?.hasPrefix("The") { if beginsWithThe { print("John‘s building identifier begins with \"The\".")
        } else { print("John‘s building identifier does not begin with \"The\".")
        }
} // prints "John‘s building identifier begins with "The"."

Note: In the example above, add a question mark after the parentheses of the method becausebuildingIdentifier()the return value is a nullable value, not the method itself, which is nullable.





Details turn from: http://wiki.jikexueyuan.com/project/swift/chapter2/07_Closures.html



An attack on the swift-------------an empty chain call


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.