Method (methods) and the following table script (subscripts)
Instance method (Instance Methods)
Type method (Type Methods)
The following table script (subscripts)
A method is a function that is associated with some particular type. Classes, structs, enumerations can define instance methods, and instance methods encapsulate specific tasks and functions for instances of a given type. Classes, structs, enumerations can also define type methods, and type methods are associated with the type itself. Type method and Objecti
The class method in Ve-c is similar methods.
The ability to define methods for structs and enumerations is one of the main differences between Swift and C/objective-c. In Objective-c, a class is the only type that can define a method. But in Swift, you can choose not only whether you want to define a class/struct/enumeration, but also the flexibility to define methods on the type you create (class/struct/enum).
1. Example method (Instance Methods)
An instance method is a method that belongs to a particular class, struct, or instance of an enumeration type. Instance methods provide a way to access and modify instance properties, or provide functionality related to an instance's purpose, and support the functionality of the instance. The syntax of the instance method is exactly the same as the function.
The instance method is written between the curly braces of the type to which it belongs. An instance method can implicitly access all other instance methods and properties of the type to which it belongs. An instance method can only be called by a specific instance of the class to which it belongs. An instance method cannot be called without being detached from an existing instance.
In the following example, a very simple Counter class is defined, and Counter can be used to count the number of times an action occurs:
class Counter {var count = 0//可变属性 countfunc increment() {//让计数器按一递增++count}func incrementBy(amount: Int) {//让计数器按一个指定的整数值递增count += amount}func reset() {//将计数器重置为0count = 0}}
The Counter class defines three instance methods:-Increment makes the counter increment by one;-IncrementBy (Amount:int) increments the counter by a specified integer value;-Reset resets the counter to 0. Counter This class also declares a mutable attribute count, which is used to keep track of the current counter value. Call an instance method with dot syntax (dot syntax), just as you would call a property:
let counter = Counter()// 初始计数值是0counter.increment()// 计数值现在是1counter.incrementBy(5)// 计数值现在是6counter.reset()// 计数值现在是0
1.1 Local parameter name and external parameter name for the method (local and External Parameter Names for Methods)
A function parameter can have both a local name (used inside the function body) and an external name (used when calling a function). The method parameter is the same (because the method is a function, but the function is related to a type).
The methods in Swift are very similar to the methods in Objective-c. Like in Objective-c, the name of a method in Swift usually uses a preposition to point to the first parameter of the method, such as: with, for, by, and so on. In the previous example of the Counter class IncrementBy (_:) That's the way it is. The use of prepositions allows methods to be interpreted like a sentence when called.
Specifically, Swift defaults to only a local parameter name for the method's first parameter name; The default gives both the second and subsequent parameter names the local parameter name and the external parameter name. This Convention is compatible with typical naming and calling conventions, similar to the way you write Objective-c. This Convention also allows the expression method to be called without qualifying the parameter name.
Take a look at another version of this Counter (which defines a more complex IncrementBy (_:) METHOD):
class Counter {var count: Int = 0func incrementBy(amount: Int, numberOfTimes: Int) {count += amount * numberOfTimes}}
IncrementBy (_:numveroftimes:) The method has two parameters: Amount and Numberoftimes. By default, Swift only treats amount as a local name, but treats Numberoftimes as a local name and as an external name. This method is called below:
let counter = Counter()counter.incrementBy(5, numberOfTimes: 3)// counter 的值现在是 15
You do not have to define an external variable name for the first parameter value: Since the function name IncrementBy (_numberoftimes:) It can be clearly seen. The second parameter, however, is bounded by an external parameter name to clarify its role when the method is called. This default behavior makes the above code mean that the method defined in Swift uses the same syntax style as objective-c, and the method is invoked in the form of a natural expression.
1.2 Modify the external parameter name of the method (modifying External Parameter name Behavior for Methods)
Sometimes it is useful to provide an external parameter name for the first parameter of a method, although this is not the default behavior. You can add an explicit external name yourself or use a pound sign (#) as the prefix for the first parameter to take the local name as an external name. Conversely, if you do not want to provide an external name for the second and subsequent arguments of the method, you can override the default behavior by using an underscore (_) as the explicit external name for the parameter.
1.3 Self attribute
Each instance of a type has an implied property called Self, which is exactly the same as the instance itself. You can use this implicit self property to refer to the current instance in an instance method of an instance.
The increment method in the above example can also be written like this:
func increment() {self.count++}
In fact, you don't have to write self frequently in your code. Whenever you use a known property or method name in a method, if you do not explicitly write self, Swift assumes that you are referring to the property or method of the current instance. This assumption has been demonstrated in the above Counter: count (not self.count) is used in the three instance methods in Counter.
The main scenario for using this rule is when an instance method has a parameter name that is the same as an instance's property name. In this case, the parameter name takes precedence and must be used in a more restrictive manner when referencing the property. You can then use the Self property to differentiate between the parameter name and the property name.
In the following example, self eliminates ambiguity between the method parameter X and the instance attribute x:
struct Point {var x = 0.0, y = 0.0func isToTheRightOfX(x: Double) -> Bool {return self.x > x}}let somePoint = Point(x: 4.0, y: 5.0)if somePoint.isToTheRightOfX(1.0) {print("This point is to the right of the line where x == 1.0")}// 打印输出: This point is to the right of the line where x == 1.0
If you do not use the self prefix, Swift thinks that X used two times refers to a function parameter with the name X.
1.4 Modifying a value type in an instance method (modifying value Types from within Instance Methods)
Structs and enumerations are value types. In general, a property of a value type cannot be modified in its instance method. However, if you do need to modify a struct or enumeration's properties in a specific method, you can choose the mutation (mutating) method, and the method can change its properties from within the method, and any changes it makes will remain in the original structure at the end of the method. The method can also assign an entirely new instance to its implied self property, and the new instance will replace the original instance after the method finishes.
To use the mutation method, place the keyword mutating before the Func keyword of the method:
struct Point {var x = 0.0, y = 0.0mutating func moveByX(deltaX: Double, y deltaY: Double) {x += deltaXy += deltaY}}var somePoint = Point(x: 1.0, y: 1.0)somePoint.moveByX(2.0, y: 3.0)print("The point is now at (\(somePoint.x), \(somePoint.y))")// 打印输出: "The point is now at (3.0, 4.0)"
The point structure above defines a mutation method (mutating methods) Movebyx (_:y:) Used to move points. Instead of returning a new point, the Movebyx method modifies the point when it is called. The method definition is prefixed with the mutating keyword, which allows the method to modify the properties of the value type.
Note: You cannot call a mutation method on a struct type constant, because a constant property cannot be changed, even if you want to change the variable property of a constant, see storing properties and instance variables for details:
let fixedPoint = Point(x: 3.0, y: 3.0)fixedPoint.moveByX(2.0, y: 3.0)// 这里将会抛出一个错误
1.5 Assigning self A value in the mutation method (assigning to self within a mutating method)
The mutation method can be assigned to an entirely new instance of the implicit property self. The above point example can be rewritten in the following way:
struct Point {var x = 0.0, y = 0.0mutating func moveByX(deltaX: Double, y deltaY: Double) {self = Point(x: x + deltaX, y: y + deltaY)}}
New Variant Method Movebyx (_:y:) A new structure is created (its x and Y values are set to the target value). Calling this version of the method and invoking the last version of the final result is the same.
The mutation method of an enumeration can set self to a different member of the same enumeration type:
enum TriStateSwitch {case Off, Low, Highmutating func next() {switch self {case Off:self = Lowcase Low:self = Highcase High:self = Off}}}var ovenLight = TriStateSwitch.LowovenLight.next()// ovenLight 现在等于 .HighovenLight.next()// ovenLight 现在等于 .Off
An enumeration of three-state switches is defined in the example above. Each time the next method is called, the switch loops before a different power state (OFF, Low, high).
2 Type methods (Type Methods)
An instance method is a method that is called by an instance of the type. You can also define a method called by the type itself, which is called a type method. Declares the struct and enum type methods, plus the keyword static before the method's func keyword. Class may use the keyword class to allow subclasses to override the implementation of the parent class.
Attention:
In Objective-c, you can only define type methods (Type-level methods) for objective-c classes. In Swift, you can define type methods for all classes, structs, and enumerations: Each type method is explicitly included by the type it supports.
Type methods are called with the same point syntax as instance methods. However, you call this method at the type level, not at the instance level. The following is an example of how to invoke a type method on a SomeClass class:
class SomeClass {class func someTypeMethod() {// type method implementation goes here}}SomeClass.someTypeMethod()
In the method body (body) of a type method, self points to the type itself, not to an instance of the type. For structs and enumerations, this means that you can use self to disambiguate between static and static method parameters (similar to what we did when we processed the instance properties and instance method parameters earlier).
In general, any unqualified method and property name will come from another type-level method and property in this class. A type method can invoke the name of another type method in this class without prefixing the method name with the type name. Similarly, struct and enum type methods can also access static properties directly from the name of a static property without requiring a type name prefix.
The following example defines a struct named Leveltracker. It monitors the player's game development (different levels or stages of the game). This is a single player game, but it can also store game information for multiple players on the same device.
At the beginning of the game, all game levels (except Level 1) are locked. Each time a player completes a level, this level unlocks all players on the device. The Leveltracker structure uses static properties and methods to monitor which level of the game has been unlocked. It also monitors the current level of each player.
struct LevelTracker {static var highestUnlockedLevel = 1static func unlockLevel(level: Int) {if level > highestUnlockedLevel { highestUnlockedLevel = level }}static func levelIsUnlocked(level: Int) -> Bool {return level <= highestUnlockedLevel}var currentLevel = 1mutating func advanceToLevel(level: Int) -> Bool {if LevelTracker.levelIsUnlocked(level) {currentLevel = levelreturn true} else {return false}}}
The Leveltracker monitors the player's unlocked highest level. This value is stored in the static property Highestunlockedlevel.
Leveltracker also defines two types of methods to work with the highestunlockedlevel. The first type method is Unlocklevel: Once the new level is unlocked, it updates the value of Highestunlockedlevel. The second type method is levelisunlocked: If a given level is already unlocked, it returns true. (Note: Although we do not use a leveltracker.highestunlockedlevel-like notation, this type method can still access the static property Highestunlockedlevel)
In addition to static properties and type methods, Leveltracker also monitors the progress of each player. It uses the instance attribute currentlevel to monitor the player's current level.
To facilitate the management of the CurrentLevel property, Leveltracker defines the instance method advancetolevel. This method checks whether the requested new level has been unlocked before updating the currentlevel. The Advancetolevel method returns a Boolean value to indicate whether the currentlevel can be set.
Below, the player class uses Leveltracker to monitor and update each player's development progress:
class Player {var tracker = LevelTracker()let playerName: Stringfunc completedLevel(level: Int) {LevelTracker.unlockLevel(level + 1)tracker.advanceToLevel(level + 1)}init(name: String) {playerName = name}}
The Player class creates a new Leveltracker instance to monitor the user's progress. It provides the Completedlevel method: Once the player completes a specified level, it is called. This method unlocks the next level for all players and updates the current player's progress to the next level. (We ignored the Boolean value returned by Advancetolevel because it was known that the level was unlocked when Leveltracker.unlocklevel was called). You can also create an instance of the player for a new player and see what happens when the player finishes the hierarchy:
var player = Player(name: "Argyrios")player.completedLevel(1)print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")// 打印输出:highest unlocked level is now 2
If you create a second player and try to get him to start a level that is not unlocked by any player, the attempt to set the player's current level will fail:
player = Player(name: "Beto")if player.tracker.advanceToLevel(6) {print("player is now on level 6")} else {print("level 6 has not yet been unlocked")}// 打印输出:level 6 has not yet been unlocked
3 Subscript Script (subscripts)
Content:
Subscript script Syntax
Subscript Script Usage
Subscript Script Options
Subscript scripts can be defined in the classes (class), struct (structure), and enumeration (enumeration) targets, which can be thought of as access to the collection (collection), list, or sequence (sequence shortcuts, Using the index of the subscript script to set and get values, you do not need to invoke the instance's specific assignment and access methods. For example, using the subscript script to access elements in an array instance can be written Somearray[index], and the elements in the Access Dictionary (Dictionary) instance can be written Somedictionary[key].
Multiple subscript scripts can be defined for the same target, overloaded with different index value types, and subscript scripts are not limited to a single latitude, and you can define the requirements for the custom type of subscript scripts for multiple incoming parameters.
3.1 Subscript Script Syntax
The subscript script allows you to access and assign values to an instance by passing in one or more index values in the brackets behind the instance. Syntax is similar to the blending of instance methods and computed properties. Similar to defining an instance method, the subscript script is defined using the SUBSCRIPT keyword to explicitly declare the in parameter (one or more) and the return type. Unlike instance methods, subscript scripts can be set to read-write or read-only. This approach is somewhat like the getter and setter of computed properties:
subscript(index: Int) -> Int {get {// 返回与入参匹配的Int类型的值}set(newValue) {// 执行赋值操作}}
The type of newvalue must be the same as the return type defined by the subscript script. The same as the computed attribute is the parameter declaration of the set newvalue even if not written, the default newvalue variable can still be used to access the newly assigned value in the set code block.
As with read-only computed properties, you can write the code that should be written in the get code block directly in subscript:
subscript(index: Int) -> Int {// 返回与入参匹配的Int类型的值}
The following code demonstrates the use of a read-only subscript script in a timestable struct that shows n times the number of incoming integers.
struct TimesTable {let multiplier: Intsubscript(index: Int) -> Int {return multiplier * index}}let threeTimesTable = TimesTable(multiplier: 3)print("3的6倍是\(threeTimesTable[6])")// 输出 "3的6倍是18"
In the example above, a timestable structure was created to represent an instance of three times times the index value. A value of 3 initializes the instance member multiplier as a struct constructor. You can get results using subscript scripts, such as Threetimestable[6]. This statement accesses the sixth element of the threetimestable and returns 3 times times 6, or 18.
Note:
The timestable example is based on a fixed mathematical formula. It is not appropriate to assign a value to Threetimestable[someindex], which is why the satellite script is only defined as read-only.
3.2 Subscript Script Usage
The subscript script also has different meanings depending on the usage scenario. Typically subscript scripts are shortcuts that are used to access elements in a collection (collection), list, or sequence (sequence). You can freely implement subscript scripts in your own particular class or struct to provide the appropriate functionality.
For example, Swift's Dictionary (Dictionary) implements access to the values stored in its instance through the subscript script. Use in subscript script
Index the same type of value as the dictionary, and assign a value of a dictionary value type to the subscript script to set the value for the dictionary:
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]numberOfLegs["bird"] = 2
The example above defines a variable named Numberoflegs and initializes a dictionary instance with three pairs of key values with a dictionary literal. The dictionary storage value type of Numberoflegs is inferred as [String:int]. After the dictionary instance is created, the integer value 2 is assigned to the location of the dictionary instance's index as bird, using the subscript script.
Attention:
In the satellite script implementation of the dictionary in Swift, the return value in the Get section is Int? , the Numberoflegs dictionary in the previous example is returned by a subordinate script
Back to an Int? or "optional int", not the index of each dictionary can get an integer value, for the index without the value of the access to return the result is nil, also want to remove from the dictionary instance the value under an index is only required to assign the index to nil.
3.3 Subscript Script Options
The subscript script allows any number of index parameters, and there is no limit to the type of entry. The return value of the subscript script can also be of any type. Subscript scripts can use variable arguments and variable parameters, but using the write read-out (in-out) parameter or setting a default value for a parameter is not allowed.
A class or struct can provide multiple subscript script implementations based on its own needs, which are differentiated by the type of the incoming parameter when the subscript script is defined, and the subscript script automatically matches the appropriate subscript script implementation to run, which is the overload of the subscript script.
A subscript script entry is the most common case, but you can define multiple subscript script entry parameters as long as there is a suitable scenario. The following example defines a matrix struct that renders a two-dimensional matrix of type Double. The subscript script for a Matrix struct requires two integer parameters:
struct Matrix {let rows: Int, columns: Intvar grid: [Double]init(rows: Int, columns: Int) {self.rows = rowsself.columns = columnsgrid = Array(count: rows * columns, repeatedValue: 0.0)}func indexIsValidForRow(row: Int, column: Int) -> Bool {return row >= 0 && row < rows && column >= 0 && column < columns}subscript(row: Int, column: Int) -> Double {get {assert(indexIsValidForRow(row, column: column), "Index out of range")return grid[(row * columns) + column]}set {assert(indexIsValidForRow(row, column: column), "Index out of range")grid[(row * columns) + column] = newValue}}}
The Matrix provides a two-entry constructor, where the entry is rows and columns, creating an array of Double types sufficient to hold the number of rows * columns. By passing in the array length and initial value 0.0 to a constructor of the array, each element in the Matrix is initialized with a value of 0.0. For the construction and destruction of arrays, refer to creating an empty array.
You can construct a new Matrix instance by passing in the appropriate number of row and column:
var matrix = Matrix(rows: 2, columns: 2)
In the example above, a new Matrix instance of two rows of two columns was created. An array instance of the matrix instance in the reading order from top left to bottom right is a flattened storage of a two-dimensional array of matrices:
// grid = [0.0, 0.0, 0.0, 0.0]col0 col1row0 [0.0, 0.0,row1 0.0, 0.0]
Assigning a value to a matrix instance expression with a row and column subscript script completes the assignment, and the subscript script entry uses a comma-delimited
matrix[0, 1] = 1.5matrix[1, 0] = 3.2
The above two statements give the matrix a value of 1.5 for the top right, and a value of 3.2 for sitting down:
[0.0, 1.5,3.2, 0.0]
The Matrix subscript script's getter and setter both invoke the row and column of the subscript script into the valid judgment. To facilitate assertions, the Matrix contains a name of Indexisvalidforrow (_:column:). Member method that confirms whether the row or column value of the entry will cause the array to be out of bounds:
func indexIsValidForRow(row: Int, column: Int) -> Bool {return row >= 0 && row < rows && column >= 0 && column < columns
Swift learns the fifth shot