Generic function
func swapTwoValues<T>(_ value1:inout T ,_ value2:inout T){
let temp = value1
value1 = value2
value2 = temp
}
var x = "str1"
var y = "Str2"
swapTwoValues(&x, &y)
Copy the code
The generic type
// The simplest implementation, Int struct Stack{private var items = [Int]() mutating func push(_ item:Int){items. Append (item)} Stack<T>{ private var items = [T]() mutating func push(_ item:T){ items.append(item) } }Copy the code
Type constraints
Syntax: When a parameter type is defined, a separate class or protocol constraint is placed after the parameter name, separated from the parameter name by a colon:. Note: Type constraints can only be classes or protocols.
Func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {} func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {}Copy the code
To place a protocol or class after a type parameter, as requiredType parameter T
followXX agreement
The compiler reported an error when the diagram User did not comply with the Equatable protocol
Association types
When defining a protocol, use an association type as a placeholder for the type in the protocol
Use of association types
Protocol StackProtocal{associatedType Item mutating func append(_ Item :Item)} struct IntStack:StackProtocal{ var items = [Int]() typealias Item = Int mutating func append(_ item: Int) {items.append(item)}} // Struct ElementStack<T>:StackProtocal{var items = [T]() typeAlias item = T mutating func append(_ item: T) { items.append(item) } } var s = IntStack() s.append(1) print(s.items)Copy the code
Storage of non-generic protocols
protocol Drawable{ func draw() } struct Point:Drawable{ var x:Double func draw() { print("Point") } } struct Line:Drawable{var x:Int func draw() {print("Line")}} // The actual type of mm is a special compiler-generated data type called let mm:Drawable = arc4random()%2 == 0 ? Point (x: 20.0) : Line(x:10) mm. Draw () //Drawable (x:10) mm. X: Drawable (x:10) mmCopy the code
As you can see from the above code, mm can represent both Point and Line types. In fact, the actual type of MM is a special data type generated by the compilerExistential Container
.Existential Container
Encapsulate specific types to achieve storage consistencyExistential Container
The type occupies five memory units (also known asword, Word). Its structure is shown in the figure below:
- Three words as a Value Buffer
- One word is used as the index of the Value Witness Table
- One word is used as the index of the Protocol Witness Table
The Value Buffer occupies three words and may store values or Pointers. For Small values (the storage space is less than or equal to the Value Buffer), they can be directly stored in the Value Buffer. For Large values (larger than or equal to the Value Buffer), memory space is allocated in the heap for storage, and the Value Buffer only stores its corresponding pointer
VWT(Value Witness Table)Is the lifecycle management of protocol types, which handles initialization, copying, destruction, etc
Protocol Witness Table (PWT) Method invocation of management protocols
Methods declared in Protocol are stored in PWT at the bottom. Methods in PWT are also found in the v-table of the class via class_method. If there are no functions declared in Protocol but a default implementation provided through Extension, whose function addresses are already determined during compilation, this method cannot be overridden for protocol-compliant classes
Storage of generic protocols
- For class/struct/enum it is used
Type parameters
To implement generics - For protocal, it adopts
Abstract type member
Abstract Type Member
The specific technology is calledAssociation types
Associated Type
Next we will look at the storage of generic protocolsUsing the non-generic protocol example, we think the above code is ok because it hasExistential Container
Type ensures storage consistency. Because there areExistential Container
Type ensures storage consistency. But we ignore that the nature of generic protocols is to constrain types, not declare them, so the compiler will report an error. And we can verify it again with the following code
let x = gen.generate()
Copy the code
What is the type of x? The x type can be either Int or String. Swift itself is a type enforcement language. All types must be determined at compile time, so Swift cannot directly support the storage of generic protocols
Type erasure
In SWIFT, protocols can have association typesAssociated Type
For generic-like functionality, but the protocol associated with the type is not a real type, so it cannot be used as a separate type declaration. The above discussion has been carried out, and the screenshot is attached:
How to deal with
As for the specific type encapsulated by generic protocol, this is actually a common solution in the industry. Many system libraries in SWIFT adopt this approach to solve the problem. The specific solution is as follows:
- Defines a mid-tier structure that implements all methods of the protocol
- In the concrete protocol method implemented by the mid-tier architecture, it is forwarded to the abstract type that implements the protocol
- During initialization of the mid-tier architecture, the abstract type of the implementation protocol is passed in as a parameter (dependency injection)