A declaration can introduce new names and constructs into your program. For example, you can use declarations to introduce functions and methods, variables and constants, or to define new named enumerations, structures, classes, and protocol types. You can also use a declaration to extend the behavior of an existing named type. Or introduce symbols in your program that are declared elsewhere.
In Swift, most declarations are in some sense initialization definitions that perform or peer declarations of them. This means that most protocol members require separate declarations because the protocol and their members do not match. For convenience, and because these distinctions are not important in Swift, declarations contain both declarations and definitions.
Episode GRAMMAR OF A DECLARATION → import-declaration → constant- DECLARATION → Variable -declaration – typeAlias -declaration – function-declaration – Enum -declaration declaration → struct-declaration declaration → class-declaration declaration → protocol-declaration Declaration → Initializer – Declaration → Deinitializer – Declaration → extension- Declaration Declaration – subscript – declaration declaration – > operator – declaration declarations > declarationdeclarationsopt Declaration – specifiers – > declaration – specifierdeclaration – specifiersopt declaration – specifiers – class | mutating | nonmutating | override | static | unowned |
Scope of the module
A module scope defines code that is visible to other source files in the module. In swift source files, the highest-level code consists of zero or more statements, declarations, and expressions. Variables, constants, and other declarations are declared at the top of a source file, making them visible to every source file in the same module.
As a developer, it is particularly important to have a learning atmosphere and a communication circle. This is my iOS development communication group: Programming Daxin, no matter you are small white or big ox, welcome to enter. Let us progress together and develop together! (The group will provide some free study books collected by the group owner and hundreds of interview questions and answers documents for free!)
GRAMMAR OF A top-level DECLARATION → statements opt
The code block
Code blocks are used to group together statements that declare and control structures. It has the following form:
1. { `statements` }
Copy the code
Statements in a code block include declarations, expressions, and various other types of statements that are executed in the order in which they appear in the source code.
GRAMMAR OF A CODE BLOCK CODE – BLOCK → statements opt
Introduce statement
Importing declarations allows you to use things declared in other files. The basic form of an import statement is to import an entire code module; It starts with the import keyword, followed by a module name:
1. import module
Copy the code
You can provide more details to restrict the notation introduced, such as declaring a particular submodule or making a particular declaration within a module or submodule. (For improvement) When you use these details, only the introduced symbols are available in the current program summary (not the whole declared module).
1. import import kind module.symbol name import module.submodule
Copy the code
Episode GRAMMAR OF AN IMPORT DECLARATION import-declaration → Attributes opt IMPORT import-kind opt import-path import-kind → Typealias | struct | class | enum | protocol | var | func import – path – import – path – identifier Import-path-identifier. Import-path import-path-identifier → identifier operator
Constant statement
Constant declarations can name a constant in your program. Constants are declared with the keyword let and follow the following format:
1. let constant name: type = expression
Copy the code
When the value of a constant is given, the constant combines the name of the constant with the original value of the expression and cannot be changed. This means that if a constant is initialized as a class, the contents of the class can be changed, but the binding relationship between the constant and the class cannot be changed. When a constant is declared as a global variable, it must be given an initial value. When a constant is declared in a class or structure, it is considered a constant property. Constants are not computable properties and therefore do not include getters and setters. (Translator’s Note: Getters and setters do not know how to translate.)
If the constant name is a progenitor, each initialization expression in the progenitor must have a value
1. let (firstNumber, secondNumber) = (10, 42)
Copy the code
In the above example, firstNumber is a constant with a value of 10 and secnodeName is a constant with a value of 42. All constants can be used independently:
1. 1 println("The first number is \(firstNumber).")
2 // prints "The first number is 10."
3 println("The second number is \(secondNumber).")
4 // prints "The second number is 42."
Copy the code
Type annotations (:type) are optional in the constant declaration and can be used to describe the types found in the Type inference interface.
To declare a static constant, use the keyword static. Static properties are described in Type Propetries.
For more information about constants or help in using them, check out the sections constants and Variables, stored Properties, and so on.
GRAMMAR OF A CONSTANT DECLARATION CONSTANT – DECLARATION → Attributes opt DECLARATION -specifiers opt Letpattern –, initializer list pattern -, initializer list – the pattern -, initializer | pattern -, initializer, Pattern-initializer -list Pattern-Initializer → Pattern Initializer opt Initializer → =expression
Variable declarations
You can declare a variable in your program using the keyword var. Depending on the declared variable type and value, such as storing and evaluating variables and properties, storing variables and property monitoring, and static variable properties, there are different declared forms. The declaration form you use depends on the scope of the variable declaration and the type of variable you intend to declare.
Note: You can also declare properties in the context of a protocol declaration, as described in type property declarations.
Stored variables and stored properties
The following form declares a stored variable or a stored variable property
1. var variable name: type = expression
Copy the code
You can use this form to declare a variable globally, in functions, or in class and struct context declarations. When a variable is declared in this form globally or within a function, it represents a stored variable. When declared in a class or structure, it represents a stored variable property.
A constructor expression can be compared to a constant declaration. If the variable name is a meta-ancestor type, the name of each element of the meta-ancestor must be the same as that of the initialization expression.
Just like the name, the value of a stored variable or the properties of a stored variable are stored in memory.
Computed variables and computed properties
Declare a stored variable or stored property as follows:
1. var variable name: type { get { statements } set(setter name) { statements } }
Copy the code
You can use this form of declaration in the context of global, function bodies, or class, struct, enumeration, and extension declarations. When a variable is declared in this form globally or within a function, it represents a computational variable. When declared in the context of class, struct, enumeration, or extension declarations, it represents a computational variable attribute.
Getters are used to read variable values, setters are used to write variable values. Setter clauses are optional, only getters are required, and you can omit all of these statements and simply return the requested value directly, as described in Read-only Computed Properites. But if you provide a setter statement, you also have to provide a getter statement.
The name of the setter and the statement in parentheses are optional. If you write a setter name, it’s going to be used as an argument to the setter. If you do not write the setter name, the initial name of the setter is newValue, as mentioned in the SETER Setter Declaration.
Unlike stored variables and stored properties, the values of computed properties and computed variables are not stored in memory.
For more information and for more examples of computed properties, see the section on Computed Properties.
Stored variable monitor and property monitor
You can use the WillSet and didSet monitors to declare a stored variable or property. A stored variable or property containing a monitor is declared as follows:
1. var variable name: type = expression { willSet(setter name) { statements } didSet(setter name { statements } }
Copy the code
You can use this form of declaration in the context of global, function bodies, or class, struct, enumeration, and extension declarations. When variables are declared globally or within a function in this form, the monitor represents a stored variable monitor; When declared in the context of class, struct, enumeration, and extension declarations, the monitor represents the property monitor.
You can add any stored properties for the appropriate monitor. You can also add any inherited attributes (whether stored or computational) to suitable monitors by overriding subclass attributes, see Overriding Properyt Observers.
Initialization expressions are optional in the declaration of a class or structure, but are required elsewhere. All variable declarations containing monitors must have type annotations, regardless of where they are declared.
The WillSet and DIDSet monitors provide a monitoring method (appropriate response) when the value of a variable or property is changed. Monitors are not run when a variable or property is first initialized; they are run only when the value is changed by an external initialization statement.
The Willset monitor runs only until a variable or attribute value is changed. The new value passes through the WillSet monitor as a constant, so it cannot be changed in a WillSet statement. The DIDSET monitor runs immediately after a variable or property value is changed. In contrast to the WillSet monitor, old variable values or properties are passed through the DidSet monitor in case you still need to get old data. This means that if you set a value in the didiset monitor statement of a variable or property itself, the new value you set will replace the one you just passed through in the WillSet monitor.
Statements with setter names and parentheses are optional in willset and DIDSET statements. If you write a setter name, it’s going to be used as an argument to willset and didSet. If you don’t write the setter name, the willSet monitor starts with newValue and the didSet monitor starts with oldValue.
Didset statements are optional when you provide a willSET statement. Similarly, when you provide a didSET statement, the Willset statement is optional.
For more information and an example of how to use property monitors, see the section, Prpperty Observers.
Class and static variable properties
The class keyword is used to declare the computational properties of a class. The static keyword is used to declare the static variable properties of a class. Classes and static variables are discussed in detail in Type Properties.
Episode GRAMMAR OF A VARIABLE DECLARATION variable-declaration → variable-declaration-headpattern-initialer-list Variable-declaration → variable-declaration-head variable-name type-annotation code-block variable-declaration → Variable-declaration-head variable-name type-annotation getter-setter-block variable-declaration → Variable-declaration-head variable-name type-annotation getter-setter-keyword-block variable-declaration → Variable-declaration-head variable-name type-annotationInitializer opt willset-didset-block variable-declaration-head → Attributes opt declaration-specifiers opt var variable-name → identifier getter-setter-block → {getter-clause Setter-clause opt} getter-setter-block → {setter-clause getter-clause} getter-clause → attributes optgetcode-block Setter-clause → attributes opt set setter-name opt code-block setter-name → (identifier) getter-setter-keyword-block → Getter-keyword-clause setter-keyword-clause opt} getter-setter-keyword-block → {setter-keyword-clause Getter-keyword-clause} getter-keyword-clause → attributes opt get setter-keyword-clause → attributes opt set Willset-didset-block → {willset-clause didset-clause opt} willset-didset-block → {didset-clause willset-clause} Willset-clause → attributes opt willSet setter-name opt code-block didset-clause → attributes opt didSet setter-name opt code-block
Alias declaration for type
Declaration of type aliases allows you to declare an alias for an existing type in your program. The alias declaration for a type begins with the keyword TypeAlias and follows the following form:
1. typealias name = existing type
Copy the code
When a type is declared by an alias, you can replace an existing type with an alias anywhere in your program. An existing type can be an already named type or a hybrid type. The alias of a type does not create a new type; it simply replaces the name of an existing type.
View more Protocol Associated Type Declaration.
GRAMMAR OF A TYPE ALIAS DECLARATION typealias-declaration → typealias-head typealias-assignment typealias-head → typealias typealias-name typealias-name → identifier typealias-assignment → =type
Function declaration
You can use function declarations to introduce new functions into your program. Functions can be declared in a class context, structure, enumeration, or protocol as methods. The function declaration uses the keyword func and follows the form:
1. func function name(parameters) -> return type { statements }
Copy the code
If the function does not return any value, the return type can be ignored as follows:
1. func function name(parameters) { statements }
Copy the code
The type of each parameter is indicated; they cannot be inferred. The parameters of the function are constant at the beginning. Add var to the front of these parameters to make them variables. Any changes to variables in scope are valid only in the body of the function, or inout is used to make these changes valid in the calling domain. For more discussion of in-out parameters, see In-out Parameters.
Functions can return multiple variables using a tuple type as a return value.
A function definition can appear in another function declaration. Such functions are called nested functions. For more discussion of nested functions, see Nestde Functions.
Parameter names
The argument to the function is a comma-separated list. The order of variables in a function call must be the same as the order of arguments in the function declaration. The simplest argument list has the following form:
1. parameter name: parameter type
Copy the code
For function parameters, the parameter name is used inside the function, not when the function is called. For method parameters, the parameter name is used in the function body and also as a label when the method is called. The first parameter name of this method is used only inside the function body, just like the parameters of the function, for example:
1. func f(x: Int, y: String) -> String { return y + String(x) } f(7, "hello") // x and y have no name class C { func f(x: Int, y: String) -> String {return y + String(x)}} let c = c () c.f(7, y: "hello") //Copy the code
You can rewrite the process by which parameter names are used as follows:
1. external parameter name local parameter name: parameter type #parameter name: parameter type _ local parameter name: parameter type
Copy the code
The second name before the local parameter makes the parameter have an extension. And different from the local parameter name. The extended parameter name must be used when the function is called. The corresponding argument must have an extension when the method or function is called.
The hash symbol (#) written before the parameter name indicates that the parameter name can be used as either an external or ontology parameter name. Equivalent to writing the local parameter name twice. When a function or method is called, the corresponding statement must contain this name.
The emphasis character (_) before the local parameter name makes the parameter nameless when the function is called. When a function or method is called, the corresponding statement must have no name.
A special type of parameter
Arguments can be ignored, values can be varied, and an initial value is provided. This method has the following form:
1. _ : <#parameter type#. parameter name: parameter type... parameter name: parameter type = default argument value
Copy the code
Arguments named with the underscore (_) are explicitly not accessible in the function body.
An argument based on the name of the underlying type, if followed by three dots (…) Is understood as a variable parameter. A function can have at most one variable argument, and it must be the last one. Mutable parameters are treated as an array of the names of the primitive types. For example, the variable int… Is regarded as int[]. For examples of variable parameters, see variADIC Parameters.
The type of the argument is followed by an expression concatenated with an equal sign (=). Such a parameter is considered to have the initial value of the given expression. If the parameter is omitted during the function call, the initial value is used. If the parameter has no win rate, it must have its own name in the function call. For example, f() and f(x:7) are both valid calls to functions with only one variable x, but f(7) is illegal because it provides a value instead of a name.
Special methods
Enumeration or struct methods decorated with self must have the mutating keyword as the function declaration header.
Methods overridden by subclasses must start with the override keyword as the function declaration header. Methods overridden without the override keyword will report an error if the override keyword is used but the parent method is not overridden.
Methods that are related to a type rather than an instance of a type must be in a static declared structure or enumeration, or in a class defined by the class keyword.
Cremation functions and methods
A Currization function or method has the following form:
1. func function name(parameters)(parameters) -> return type { statements }
Copy the code
The return value of a function defined in this form is another function. For example, the following two declarations are equivalent:
1. func addTwoNumbers(a: Int)(b: Int) -> Int { return a + b } func addTwoNumbers(a: Int) -> (Int -> Int) { func addTheSecondNumber(b: Int) -> Int { return a + b } return addTheSecondNumber } addTwoNumbers(4)(5) // Returns 9
Copy the code
Multistage Corrification is applied as follows
GRAMMAR OF A FUNCTION DECLARATION function-declaration → function-head function-name generic-parameter-clause Optfunction-signature function-body function-head → Attributes opt declaration- speciFIERS optfunc function-name → Optfunction-signature function-body function-head → Attributes opt declaration-specifiers optfunc function-name → Identifier operator function-signature → parameter-default function-result opt function-result → ->attributes opt type Function-body → code-block parameter-clause → parameter-clause → () (parameter-list… Opt) parameter-list → parameter parameter,parameter-list parameter → inout opt let opt#optparameter-name Local-parameter-name opt type-annotation default-argument-clause opt parameter → Inoutoptvar# optparameter-namelocal-parameter-name opt type-annotationdefault-argument-clause optparameter → attributes Opt type parameter-name → identifier _ local-parameter-name → identifier _ default-argument-clause → =expression:
Enumeration declarations
Use an enumeration declaration in your program to introduce an enumeration type.
Enumeration declarations take two basic forms, using the keyword enum. Enumeration declaration bodies use zero-based variables — called enumeration events — and any number of declarations, including computational properties, instance methods, static methods, constructors, type aliases, and even other enumerations, structures, and classes. Enumeration declarations cannot contain destructors or protocol declarations.
Not like a class or a structure. Enumerated types do not provide an implicit initial constructor; all constructors must be explicitly declared. The constructor can delegate other constructors in the enumeration, but the construction process is complete only when the constructor completes an enumeration time.
Like structures but unlike classes, enumerations are value types: instances of enumerations are copied when assigned to variables or constants, or when called by functions. For more information on Value Types, see the section Structures and Enumerations Are Value Types.
You can extend enumerated types, as discussed in Extension Declaration.
Enumeration of any event type
The following form declares an enumeration variable containing an enumeration time of any type
1. enum enumeration name { case enumeration case 1 case enumeration case 2(associated value types) }
Copy the code
This form of enumeration declaration is sometimes called discrinminated in other languages.
In this form, each block of events begins with the keyword case, followed by one or more enumeration events separated by commas. Each event name must be unique. Each event can also specify the value of the specified type it stores, which is specified in the ancestor of the associated value type, immediately after the event name. For more information and examples on associated value types, see the associated Values section.
Use enumerations of raw event values
The following form declares an enumeration containing enumeration events of the same base type:
1. enum enumeration name: raw value type { case enumeration case 1 = raw value 1 case enumeration case 2 = raw value 2 }
Copy the code
In this form, each block of events begins with a case keyword, followed by one or more enumeration events separated by commas. Unlike the first type of enumeration event, this type of enumeration event contains an underlying value of the same type, called a raw value. The types of these values are specified in the raw value type and must be literal integers, floating point numbers, characters, or strings.
Each event must have a unique name and must have a unique initial value. If the initial value type is specified as int, events do not have to be explicitly specified; they are implicitly labeled with values 0, 2, and so on. Each unassigned Int time is implicitly assigned an initial value, and is incremented automatically.
1. num ExampleEnum: Int { case A, B, C = 5, D }
Copy the code
In the example above, the value of ExampleEnum.A is 0, and the value of ExampleEnum. Because the value of ExampleEnum.C is explicitly set to 5, the value of ExampleEnum.D automatically grows to 6.
The initial value of the enumeration event can be obtained by calling the method roRaw, such as ExampleEnum.b.toraw (). You can also find the event using the initial value by calling the fromRaw method and return an optional event. For more information and information about getting events of the initial value type, see Raw Values.
Get enumeration events
Using dot (.). To refer to the enumeration types of events, such as EnumerationType EnumerationCase. When an Enumeration type can be inferred from context, you can omit it (. Still needed), see Enumeration Syntax and explicit Member Expression.
Use switch statements to verify the Values of Enumeration events, as described in the Matching Enumeration Values with a Switch Statement section.
The Enumeration type is pattern-matched. In contrast, the Enumeration event matching in the Case block of the Switch statement is described in Enumeration case Pattern.
GRAMMAR OF AN ENUMERATION DECLARATION enum- DECLARATION → attributesoptUnion -style-enum Attributesoptraw -value-style-enum Union-style -enum → enum-namegeneric-parameter-clauseopt{union-style-enum-membersopt} union-style-enum-members → enum-namegeneric-parameter-clauseopt{union-style-enum-membersopt} union-style-enum-members → Union-style -enum-membersopt union-style-enum-member → declaration union-style-enum-case-clause Union-style -enum-case-list union-style-enum-case-list → attributesoptCaseunion-style -enum-case-list → attributesoptCaseunion-style -enum-case-list → The union – style – enum – case union – style – enum – case, the union – style – enum – case – the list union – style – enum – case – > Enum -case-nametuple-typeopt enum-name → identifier enum-case-name → identifier raw-value-style-enum → Identifier Enum – namegeneric – parameter – clauseopt: type – identifier (raw value – style – enum – membersopt} raw – value – style – enum – members – > Raw – value – style – enum memberraw – value – style – enum – membersopt raw – value – style – enum – member – > declaration Raw – value – style – enum – case – clause raw – value – style – enum – case – clause – attributesoptcaseraw – value – style – enum – case – the list Raw – value – style – enum – case – the list – raw – value – style – enum – case raw – value – style – enum – case, raw – value – style – enum – case – the list Raw-value-style enum-case → enum-case-nameraw-value-assignment =literal
Structure declaration
Using structure declarations can introduce a structure type into your program. Struct declaration uses the struct keyword and follows the form:
1. struct structure name: adopted protocols { declarations }
Copy the code
The structure body contains zero or more declarations. These declarations can include stored and computed properties, static properties, instance methods, static methods, constructors, type aliases, and even other structure, class, and enumeration declarations. Structure declarations cannot contain destructors or protocol declarations. For a detailed discussion of and containing examples of multiple structure declarations, see the section classes and Structures.
A structure can contain any number of protocols, but cannot inherit from classes, enumerations, or other structures.
There are three ways to create a declared instance of a structure: – Call constructors declared in the body of a structure. See initializers section. — If no constructors are declared, call each constructor of the Structure. See Memberwise Initializers for Structure Types. — If no destructors are declared, all properties of the Structure have initial values, call the default constructor of the Structure, See Default Initializers for details. For the construction of a structure, see initiaization. Struct instance attributes can be used with dots (.). For details, see the Accessing Properties section. Structs are value types; An instance of a structure is copied when it is given a variable or constant and called by a function. For more information about Value Types, see the section Structures and Enumerations Are Value Types. You can use Extension declarations to extend the behavior of struct types, see Extension Declarations.
GRAMMAR OF A STRUCTURE DECLARATION struct- DECLARATION → Attributesoptstructstruct – namegeneric – parameter – clauseopttype – inheritance – clauseoptstruct – body struct – name – identifier Struct – body – > {declarationsopt}
Class declaration
You can use class declarations in your programs to introduce a class. The class declaration uses the keyword class and follows the form:
1. class class name: superclass, adopted protocols { declarations }
Copy the code
A class contains zero or more declarations. These declarations can include stored and computed properties, instance methods, class methods, constructors, individual destructor methods, type aliases, and even other structure, class, and enumeration declarations. Class declarations cannot contain protocol declarations. See the class and Struct section for a detailed discussion of and containing examples of multi-class declarations.
A class can inherit only one parent, superclass, but can contain any number of protocols. These superclasses first appear in type-inherit-clause, following any protocol.
As mentioned in the Initializer Declaration, classes can have specified and convenient constructors. When you declare any of the constructors, you can mark the constructor with the requierd variable, requiring any subclass to override it. The constructor of the specified class must initialize all declared properties of the class, which must be executed before the subclass constructor is called.
A class can override properties, methods, and the constructors of its superclass. Methods and properties overridden must be annotated with Override.
While the property and method declarations of a superclass can be inherited by the current class, the specified constructor of the superclass declaration cannot. This means that if the current class overrides all of the specified constructors of the superclass, it inherits the convenience constructors of the superclass. Swift’s classes do not inherit from a global base class.
There are two ways to create instances of declared classes:
- Call a constructor in the class. See Initializers.
- If no constructors are declared and all attributes of the class are assigned initial values, call the default constructors of the class. See Default Initializers.
Class instance attributes can be used with dot (.) For details, see the Accessing Properties section.
Classes are reference types; When a constant or variable is assigned and a function is called, an instance of a class is referenced, not copied. For more information on reference Types, Structures and Enumerations Are Value Types section.
You can use Extension declarations to extend the behavior of classes. See Extension Declarations.
Episode 262: A CLASS DECLARATION – DECLARATION → Attributesoptclassclass – namegeneric – parameter – clauseopttype – inheritance – clauseoptclass – body class – the name and identifier Class – the body – > {declarationsopt}
Statement of Agreement
A protocol declaration introduces a named protocol type to your program. Protocol declarations are declared using the protocol keyword and have the following form:
1. protocol protocol name: inherited protocols {
2. protocol member declarations
3. }
Copy the code
The body of the protocol contains zero or more protocol member declarations that describe the conformance requirements that must be met for any adoption of the protocol. In particular, a protocol can declare consistency types of properties, methods, initializers, and associated scripts that must be implemented. Protocols can also declare type aliases for special classes, called associative types, that specify relationships between different declarations of the protocol. The agreement membership declaration is discussed in detail below.
Protocol types can be inherited from many other protocols. When a protocol type inherits from another protocol, all requirements from the other protocols are aggregated, and any type inheriting from the current protocol must meet all of these requirements. For an example of how to use protocol inheritance, see Protocol inheritance
Note: You can also use protocol composition types to set conformance requirements for multiple protocols, see Protocol Composition types and Protocol Composition for details
You can add protocol consistency to a previously declared type by adopting the protocol in the extension declaration of the type. In the extension you must implement all the requirements for adopting the protocol. If all requirements are met for the type, you can leave the subject of the extension declaration blank.
By default, a protocol type must implement all properties, methods, and dependencies declared in the protocol. That is, you can tag these protocol member declarations with the Optional attribute to specify that their conformance type implementations are optional. The optional attribute can only be used for protocols marked with the objC attribute. The result is that only class types can adopt and comply with protocols that require optional members. For more information on how to use the optional attribute and guidance on how to access optional protocol members — such as when you are not sure whether consistent types implement them — see Optional Protocol Requirements
To limit protocol adoption to class types only, the entire protocol declaration needs to be marked with the class_protocol attribute. Any protocol that inherits from a protocol marked with the class_protocol attribute can be intelligently adopted only by class types.
Note: If the protocol is already marked with the object attribute, the class_protocol attribute implicitly applies to the protocol; It is no longer necessary to flag the protocol explicitly with the class_protocol attribute.
Protocols are named types, so they can appear everywhere in your code as another named type, as discussed in protocol types. However, you cannot construct an instance of a protocol because protocols don’t actually provide implementations of the requirements they specify.
You can use protocols to declare the methods of a class’s proxy or the structure it should implement, as described in the delegate (proxy) pattern.
Agreement statement syntax protocol – declaration – attributesoptprotocolprotocol – nametype – inheritance – clauseoptprotocol – body protocol – name – > Identifier protocol-body → {protocol-member-declarationsopt} protocol-member-declaration → Protocol-property-declaration protocol-member-declaration → protocol-method-declaration protocol-member-declaration → Protocol, initializer – declaration protocol – member – declaration – protocol – subscript – declaration Protocol – member – declaration – protocol – associated – type – declaration protocol – member – and declarations protocol-member-declarationprotocol-member-declarationsopt
Protocol Attribute Declaration
The protocol states that conformance types must implement a property in the body of the protocol declaration by introducing a protocol property declaration. Protocol attribute declarations have a special type declaration form:
1. var property name: type { get set }
Copy the code
Like other protocol member declarations, these property declarations declare getter and setter requirements only for types that conform to the protocol. The result is that you don’t need to implement getters and setters in the protocol where it’s declared.
Getter and setter requirements can be met in a variety of ways through consistency types. If the property declaration contains get and set keywords, consistency types can be stored variable properties or computed properties that are read-write (implementing getters and setters), but cannot be implemented as constant properties or read-only computed properties. If the property declaration contains only the GET keyword, it can be implemented as an attribute of any type. For example, a conformance type that implements the protocol’s attribute requirements, see Attribute Requirements
See variable declarations for more
Protocol property declaration syntax protocol-property-declaration → variable-declaration-headvariable-nametype-annotationgetter-setter-keyword-block
Protocol method Declaration
The protocol states that the consistency type must implement a method by introducing a protocol method declaration in the body of the protocol declaration. Protocol method declarations and function method declarations have the same form and contain the following two rules: They do not include function bodies, and you cannot provide initial values for their arguments in class declarations. For example, the conforming type implements the methods required by the protocol. See the required methods section.
You can use the class keyword to declare a class or a required static method in a protocol declaration. The classes that perform these methods are also declared with the keyword class. Instead, structures that perform these methods must be declared with the keyword static. If you want to use extension methods, use the class keyword when extending classes and the static keyword when extending structures.
See function declarations for more.
Episode 262: Episode 262: A PROTOCOL METHOD DECLARATION protocol-method- DECLARATION → function-headfunction-namegeneric-parameter-clauseoptfunction-signature
Protocol constructor declaration
The protocol states that the conformance type must implement a constructor by introducing a protocol constructor declaration in the body of the protocol declaration. A protocol constructor declaration has the same form as a constructor declaration, except that it does not contain a constructor. See constructor declarations for more information.
Episode GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION PROTOCOL – INITIALIZER – DECLARATION → initializer-headgeneric-parameter-clauseoptparameter-clause
Protocol dependency script declaration
The protocol states that conformance types must be implemented in the body of the protocol declaration by introducing a protocol dependency script declaration. Protocol property declarations have a special form for attached script declarations:
subscript (parameters) -> return type { get set }
Dependency script declarations declare only the minimum number of getters and setters required for protocol-consistent types. If the accessory script declaration contains the GET and set keywords, the consistent type must also have a getter and setter statement. If the accessory script declares the value to contain the GET keyword, the consistent type must contain at least one getter statement, optionally including setter statements.
See dependency script declarations for more.
Episode GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION protocol-subscript- DECLARATION → subscript-headsubscript-resultgetter-setter-keyword-block
Protocol related type declaration
Typealias is used for protocol declaration related types. A related type provides an alias for a type that is part of a protocol declaration. Related types are similar to type parameters in parameter statements, but they contain the self keyword in the declared protocol. In these statements, self refers to the possible types that are consistent with the protocol. For more information and examples, see related types or type alias declarations.
GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION protocol-associated TYPE – DECLARATION → typealias-headtype-inheritance-clauseopttypealias-assignmentopt
Constructor declaration
Constructor declarations introduce constructors for classes, structs, or enumerations within a program. The constructor is declared using the keyword Init and follows two basic forms.
Structs, enumerations, classes can have any number of constructors, but the rules and behavior of class constructors are different. Unlike constructs and enums, classes have two types of constructs, designed initializers and Convenience initializers. See section Constructors.
The specified constructor for a structure, enumeration, and class is declared as follows:
1. init(parameters) { statements }
Copy the code
The specified constructor of a class initializes all attributes of the class directly. If a class has a superclass, it cannot call the other constructors of that class; it can only call one of the specified constructors of the superclass. If the class inherits any attributes from its superclass, those attributes must be assigned or modified within the current class with a specified constructor for the superclass.
Specifies that a constructor can be declared in the context of a class declaration, so it cannot be added to a class using methods that extend the declaration.
Constructors for structures and enumerations can delegate one fire to the entire initialization process with other declared constructors.
The keyword convenience is used to declare the convenience constructor of a class:
1. convenience init(parameters) { statements }
Copy the code
A convenience constructor can delegate initialization to another convenience constructor or to a specified constructor of a class. This means that the initialization of a class must end with a call to the specified constructor that fully initializes all of the class attributes. The convenience constructor cannot call the constructor of the superclass.
You can use the requierd keyword to mark the convenience constructor and the specified constructor as mandatory for every subclass constructor. Because specified constructors are not inherited by subclasses, they must be executed immediately. When a subclass directly executes all of the specified constructors of the superclass (or overwrites the specified constructors using the convenience constructors), the required convenience constructors can be either implicitly executed or inherited. Unlike methods and attached scripts, you do not need to annotate the overrride keyword for these overridden constructors.
For more examples of constructors with different declared methods, see the construction process section.
Episode 302: DECLARATION OF AN INITIALIZER – DECLARATION → , initializer headgeneric – parameter – clauseoptparameter – clauseinitializer – body, initializer – head – > Attributesoptconvenienceoptinit, initializer – body – > code – block
Destructor statement
A destructor declaration declares a destructor for a class. The destructor takes no arguments and follows the following format:
1. deinit { statements }
Copy the code
The destructor is automatically called when the class is about to be released without any statements. Destructors can only be declared once in the declaration body of a class — but not in the extension declaration of a class; there can be at most one per class.
A subclass inherits its superclass’s destructor, which is implicitly called when the subclass is about to be released. Subclasses are not released until all destructors have been executed.
The destructor is not called directly.
For examples and how to use destructors in class declarations, see the destructor procedure section.
GRAMMAR OF A DEINITIALIZER DECLARATION DEINITIALIZER – DECLARATION → AttributesoptDeinitcode -block
Extension declaration
Extension declarations are used to extend the behavior of an existing class, structure, or enumeration. The extension declaration starts with the keyword extension and follows the following rules:
1. extension type: adopted protocols { declarations }
Copy the code
An extended declaration body contains zero or more declarations. These declarations can include computational properties, computational static properties, instance methods, static and class methods, constructors, accessory script declarations, and even other structure, class, and enumeration declarations. Extension declarations cannot contain destructors, protocol declarations, storage properties, property monitors, or other extension properties. For a detailed discussion and look at examples that contain multiple extension declarations, see the extension section.
Extension declarations can add consistent protocols to existing classes, structures, and enumerations. Extension declarations cannot add inherited classes to a class, so type-inherit-clause is an extension declaration that contains only a list of protocols.
Properties, methods, and constructors of existing types cannot be overridden by extensions of their types.
Extension declarations can include constructor declarations, which means that if the type you extend is defined in another module, the constructor declaration must delegate another constructor declared in that module to properly initialize it.
GRAMMAR OF AN EXTENSION DECLARATION Extensiontype identifiertype – inheritance – clauseoptextension – body extension – the body – > {declarationsopt}
Statement with Translated Script
Accessory scripts are used to add accessory script support to specific types, usually to provide syntactic convenience when accessing elements of collections, lists, and sequences. The dependency script declaration uses the keyword subscript and is declared as follows:
Subscript (parameter) -> (return type){get{statements} set(setter name){statements}} Subscript (parameter) -> (return type){get{statements} set(setter name){statements}} The extension and protocol declaration context are declared.
Parameters specify one or more indexes that can be used to access elements (for example, I in the expression object[I]) in attached scripts of the related type. Although the index used for element access can be of any type, each variable must contain a type annotation that specifies each index type. Return Type Specifies the type of the element to be accessed.
Like computational properties, dependency script declarations support read and write operations on access elements. Getters are for reading values and setters are for writing values. Setter clauses are optional, and when only a getter clause is required, you can simply ignore both and return the requested value. That is, if you use a setter clause, you must use a getter clause.
The name of the setter and the enclosing parentheses are optional. If a setter name is used, it is treated as the name of the variable passed to the setter. If a setter name is not used, the variable name passed to the setter defaults to value. The setter name must have the same type as the return type.
You can override a satellite script in the type it declares, as long as the parameters or return type is different from the previous one. At this point, you must declare the override dependencies using the override keyword. (Note: What a mess! Is it overloading or overwriting? !).
Dependency scripts can also be declared in the context of Protocol declarations, as described in the Protocol Subscript Declaration.
For more examples of ancillary scripts and ancillary script declarations, see Subscripts.
Episode GRAMMAR OF A SUBSCRIPT DECLARATION SUBSCRIPT – DECLARATION → SUBSCRIPT -headsubscript-resultcode-block Subscript-declaration → subscript-headSubscript-resultgetter-setter-block subscript-declaration → Subscript headsubscript – resultgetter – setter – keyword – block subscript – head – > attributesoptsubscriptparameter – clause Subscript – result – > – > attributesopttype
Translated operator Statement
Operator declarations introduce infix, prefix, or postfix operators into the program using the context keyword operator declarations. Three different infixes can be declared: infixes, prefixes, and suffixes. The affixality of an operator describes the position of the operator relative to its operands. There are three basic forms of operator declarations, one of each infix. The affixality of operators is specified by adding the context keywords infix, prefix, or postfix between operator and operator. In each form, the operator name can only contain operator characters defined in Operators.
The following form declares a new infix operator:
operator infix operator name{ precedence precedence level associativity associativity }
Infix operators are binary operators that can be placed between two operands, such as the addition operator (+) in the expression 1 + 2.
Infix operators optionally specify priority, associativity, or both.
The precedence of an operator can specify how tightly the operator is bound to its operands without parentheses. You can use the precedence keyword and precedence level to specify the precedence of an operator. The priority can be any number between 0 and 255 (decimal integer); Unlike decimal integer literals, it cannot contain any underscore characters. Although the priority is a specific number, it is only used for comparison (size) with another operator. That is, when an operand can be used by two operators at the same time, such as 2 + 3 * 5, the higher-priority operator will bind the operand first.
Associativity of operators can specify the order in which operators of the same priority are grouped without parentheses. You can use the context keyword associativity along with associativity to specify the associativity of an operator, where associativity can be any of the context keywords left, right, or None. Left-associative operators are grouped from left to right. For example, the subtraction operator (-) is left associative, so 4-6 is grouped in the form of (4-5) -6, resulting in -7. Right-associative operators are grouped from right to left, and for non-associative operators set to None, they are not grouped in any way. Non-associative operators of the same precedence may not be adjacent to each other. For example, the expression 1 < 2 < 3 is illegal.
Infix operators that declare without specifying any precedence or associativity are initialized to 100 and none for associativity.
The following form declares a new prefix operator:
operator prefix operator name{}
Prefix operators immediately preceding operands are unary operators, such as the prefix increment operator (++) in the expression ++ I.
Precedence is not specified in the declaration of the prefix operator. The prefix operator is nonassociative.
The following form declares a new postfix operator:
operator postfix operator name{}
The postfix operators immediately following the operands are unary operators, such as the prefix increment operator (++) in the expression i++.
As with prefix operators, precedence is not specified in the declaration of postfix operators. Postfix operators are nonassociative.
Once you declare a new operator, you need to declare a function with the same name as the operator to implement the operator. See Custom Operators for details on how to implement a new operator.
Episode GRAMMAR OF AN OPERATOR DECLARATION operator-declaration → prefix-operator-declaration postfix-operator-declaration >infix-operator-declaration prefix-operator-declaration → operator prefix operator{} postfix-operator-declaration → Operator postfix operator{} infix-operator-declaration → operatorInfixoperator {infix-operator-attributesopt} Infix -operator-attributes → precedence-clauseoptassociativity- Clauseopt precedence-clause → precedenceprecedence-level Precedence – level – Digit 0 through 255 associativity – clause – associativityassociativity associativity and left right none