Protocol (Protocol)

Protocols can be used to define declarations of methods, attributes, and subscripts. Protocols can be followed by structures, enumerations, and classes. (Use commas to separate multiple protocols.)

protocol Drawable {
    func draw(a)				// Methods cannot have default arguments
    var x: Int { set get }  // Read-write attributes
    var y: Int { get }  	// Read-only attribute
    subscript(index: Int) -> Int { set get }  // Read-write subscripts
}

protocol Test1 {}protocol Test2 {}protocol Test3 {}class TestClass: Test1.Test2.Test3 {}// Multiple protocols are separated by commas
Copy the code

Note:

  1. Methods in protocols cannot have default values
  2. By default, everything in the protocol must be implemented. (There are exceptions, such as the option keyword of OC)

Properties in the protocol

  • Attributes defined in the protocol must be usedvarThe keyword. (Reason: read-only attribute in protocol, value may change when using computed attribute implementation)
  • When implementing the protocol, the attribute permissions must be no smaller than those defined in the protocol.
    1. As defined in the protocolget setProperty, usingvarStore properties orget setCompute attribute implementation.
    2. As defined in the protocolgetProperty, which can be implemented with any property.
protocol Drawable {
    func draw(a)
    var x: Int { set get }
    var y: Int { get }
    subscript(index: Int) -> Int { set get}}class Person1: Drawable {
    func draw(a) {
        print("Person draw")}var x: Int = 0   // Use storage properties
    var y: Int = 0
    subscript(index: Int) -> Int {
        get { 10 }
        set{}}}class Person2: Drawable {
    func draw(a) {
        print("Person draw")}var x: Int {  // Implement using computed properties
        set {}
        get { 10}}var y: Int {
        set {}
        get { 10}}subscript(index: Int) -> Int {
        get { 10 }
        set{}}}Copy the code

The static, class

To ensure generality (take care of structs and enumerations), the static keyword must be used in the protocol to define type methods, type attributes, and type subscripts.

protocol Drawable { 
    static func draw(a)  // You must use static. Using class results in an error
}
class Person1: Drawable {
    class func draw(a){  The class keyword can be used when implementing type methods in the protocol
        print("Person1 draw")}}class Person2: Drawable {
    static func draw(a) {  The static keyword can also be used when the class implements type methods in the protocol
        print("Person2 draw")}}struct Person3: Drawable {
    static func draw(a) {   // Only the static keyword can be used when structs implement type methods in the protocol
        print("Person3 draw")}}Copy the code

mutating

The implementation of a structure or enumeration is allowed to modify its own memory only if the instance method in the protocol is marked mutating. Class implementation does not require mutating, enumeration, struct.

protocol Drawable {
    mutating func draw(a)
}
class Person1: Drawable {
    var age: Int = 0
    func draw(a) {
        self.age = 12   // Class does not need mutating
        print("Person1 draw")}}struct Person2: Drawable {
    var weight: Int = 0
    mutating func draw(a) {
        self.weight = 22   // To modify storage properties in a struct, add mutating to the method
        print("Person2 draw")}}Copy the code

init

  1. Initializers can also be defined in the protocolinit,finalClass implementation must addrequired. (finalClass does not allow inheritance.
  2. If the initializer implemented from the protocol happens to be an initializer that overrides the parent class, then that initializer must be added at the same timerequiredandoverrideThe keyword.
protocol Drawable {
    init(x: Int.y: Int)
}
class Person: Drawable {
    required init(x: Int.y: Int){}// required ensures that all of its subclasses must implement this initializer
}
final class Student: Drawable {  // Final modified classes cannot be inherited
    init(x: Int.y: Int){}}Copy the code
protocol Liable {
    init(age: Int)
}
class Person {
    init(age: Int){}}class Student: Person.Liable {
    required override init(age: Int) {  // Override is an override of the parent class.
        super.init(age: age)
    }
}
Copy the code

Init, init? And init!

  1. As defined in the protocolinit?,init!, you can useinit init? init!To achieve
  2. As defined in the protocolinit, you can useinit init!To achieve them.
protocol Liable {
    init(a)
    init?(age: Int)
    init!(no: Int)
}

class Person: Liable {
    required init(a) {}
    // required init! () {}
    
    required init?(age: Int) {}
// required init(age: Int) {}
// required init! (age: Int) {}
    
    required init!(no: Int) {}
// required init(no: Int) {}
// required init? (no: Int) {}
}
Copy the code

Inheritance of agreement

One protocol can inherit from another

protocol Runnable {
    func run(a)
}
protocol Liable: Runnable {
    func breath(a)
}
class Person: Liable {
    func breath(a) {}
    func run(a){}}Copy the code

Protocol combinations

Combination of protocols that can contain a class type (up to one)

protocol Runnable {}
protocol Liable{}
class Person {}

// Accept instances of Person and its subclasses
func fn0(obj: Person) {}
// Accept instances of compliance with the Inactive agreement
func fn1(obj: Liable) {}
// accept instances that comply with both the active and Runnable protocols
func fn2(obj: Liable & Runnable) {}
// Accepts both the active and Runnable protocols and is an instance of Person or a subclass of Person
func fn3(obj: Person & Liable & Runnable) {}

typealias RealPerson = Person & Liable & Runnable
// Accepts both the active and Runnable protocols and is an instance of Person or a subclass of Person
func fn4(obj: RealPerson) {}
Copy the code

CaseIterable

Making enumerations conform to the CaseIterable protocol allows you to iterate over an enumeration value.

enum Season: CaseIterable {
    case spring, summer, automn, winter
}

let seasons = Season.allCases
print(seasons.count)

for season in seasons {
    print(season)
}
Copy the code

CustomStringConvertible

Keep CustomStringConvertible, CustomDebugStringConvertible agreement, can be custom print string instance. (Similar to description in OC, toString in Java)

class Person: CustomStringConvertible.CustomDebugStringConvertible {
    var age = 0
    var description: String {
        "person_\(age)"
    }
    var debugDescription: String {
        "debug_person_\(age)"}}let person = Person(a)print(person)
debugPrint(person) Output: person_0 debug_person_0Copy the code
  • Print callsCustomStringConvertibleDescription in protocol
  • The debugPrint callsCustomDebugStringConvertibleDebugDescription in the protocol

Any、 AnyObject

Swift provides two special types: Any and AnyObject

  • Any: can represent any type (enumerations, structs, classes, and also function types)
  • AnyObject: can stand for anyclassType (after protocolAnyObjectOnly classes can comply with this protocol.
var stu: Any = 10  // Define a variable that stores any type of variable
stu = "Long"
stu = Student(a)// var data = Array<Any>()
var data = [Any] ()// Store an array of any type
data.append(1)  // Int
data.append(3.14)  // Double
data.append(Student()) / / object
data.append("long") / / string
data.append({10})  // Closure expression
Copy the code

Is, the as? And the as! And as

Is is used to check whether the type is a certain type, and AS is used to cast the type.

protocol Runnable {
    func run(a)
}
class Person {}
class Student: Person.Runnable {
    func run(a) {
        print("Student run")}func study(a) {
        print("Student study")}}Copy the code
var stu: Any = 10
print(stu is Int) // true
stu = "Long"
print(stu is String) // true
stu = Student(a)print(stu is Student) // true
print(stu is Person)  // true
print(stu is Runnable) // true
Copy the code
var stu: Any = 10
(stu as? Student)?.study() // Study is not called
stu = Student()
(stu as? Student)?.study() // Student study
(stu as! Student).study()  // Student study, forced unpacking is risky and may crash if stU is not of Student type
(stu as? Runnable)?.run() // Student run
Copy the code

As is used when it is clearly known that it can be transferred

Var arr = [Any]() arr.append(10 as AnyCopy the code

X. elf, X. type, and AnyClass

  1. x.selfIs a pointer to a metadata. metadata holds type-related objects.
  2. x.selfx.Typetype
class Person {}
class Student: Person {}

var perType: Person.Type = Person.self
var stuType: Student.Type = Student.self
perType = stuType   // A parent pointer points to a subclass object

var anyType: AnyObject.Type = Person.self
anyType = Student.self

public typealias AnyClass = AnyObject.Type
var anyType2: AnyClass = Person.self
anyType2 = Student.self

var per = Person(a)var perType = type(of: per)  // Get the metatype of the instance
print(Person.self = = type(of: per))  // true
Copy the code

The application of meta-types

class Animal{ required init(a){}}// Make sure all subclasses implement init
class Cat: Animal {}
class Dog: Animal {}
class Pig: Animal {}

func create(_ clses: [Animal.Type])- > [Animal] {
    var arr = [Animal] ()for cls in clses {
        arr.append(cls.init()}return arr
}
print(create([Cat.self.Dog.self.Pig.self]))
Copy the code
class Person {
    var age: Int = 0
}
class Student: Person {
    var no: Int = 0
}

print(class_getInstanceSize(Student.self))  / / 32
print(class_getSuperclass(Student.self)!)  // Person
print(class_getSuperclass(Person.self)!)   // Swift._SwiftObject
Copy the code

As you can see from the results, Swift also has a hidden base class. Swif._swiftobject source: github.com/apple/swift…

Self

Self represents the current type.

class Person {
    var age = 1
    static var count = 2
    
    func run(a) {
        print(self.age)
        print(Self.count)
    }
}
Copy the code

Self is typically used as a return value type, specifying that the return value and the method caller must be of the same type (and can also be used as a parameter type). This is similar to OC InstanceType.

protocol Runnable {
    func test(a) -> Self
}
class Person: Runnable {
    required init(a) {}
    func test(a) -> Self {
        type(of: self).init()}}class Student: Person  {}

var per = Person(a)print(per.test())  // Person

var stu = Student(a)print(stu.test())  // Student
Copy the code

Reference:

MJ Swift from Door to Mastery course

Apple Developer Documentation