This post was originally posted on my blog

preface

Protocol, the development experience should be familiar, many languages have protocols, but relatively speaking, Swift protocol is more powerful, flexible.

  • A declaration of protocols in Swift that can be used to define methods, attributes, and subscripts. Protocols can be enumerated, structs, and classes (separated by commas).
// protocol Drawable {// func draw() var x: Int {getsetVar y: Int {get} // subscript(index: Int) -> Int {getset}}Copy the code

Class TestClass holds multiple protocols

protocol Test1 { }
protocol Test2 { }
protocol Test3 { }
class TestClass : Test1, Test2, Test3 { }
Copy the code

One thing to note

  • Methods defined in protocols cannot have default parameter values
  • By default, everything defined in the protocol must be implemented
  • There’s a way to do it and only partially implement it, as we’ll see later

Properties in the protocol

  • The var keyword must be used to define attributes in the protocol
  • When implementing the protocol, the property permissions must be no less than those defined in the protocol
  • The protocol defines GET and set, and uses var to store attributes or get and set to calculate attributes
  • The protocol defines GET, which can be implemented with any property

Drawable (Drawable, Drawable, Drawable, Drawable, Drawable); The attribute must use the var keyword

// protocol Drawable {func draw() var x: Int {getsetVar subscript(index: Int) -> Int {get} var subscript(index: Int) -> Int {getset} // subscript}Copy the code

When implemented, there’s the following way,

Class Person: Drawable {var x: Int = 0let y: Int = 0 //letImplement the read-only property funcdraw() {
        print("Person draw")
    }
    subscript(index: Int) -> Int {
        set { }
        get { index }
    }
}
Copy the code

Of course. Or you could write it like this

Class Person: Drawable {var x: Int {// get {0}set{}} var y: Int {0} //var implements read-only attribute funcdraw() { print("Person draw") }
    subscript(index: Int) -> Int {
        set { }
        get { index }
    }
}
Copy the code

The static, class

  • To ensure generality, the protocol must use static to define type methods, type attributes, and type subscripts
    • Because class can only be used in classes, not structures, etc. So static for general purpose
    • Class = static; class = static;
Protocol Drawable {// here must use static static func draw()} class Person1: Drawable {// here can use class class funcdraw() {
        print("Person1 draw"}} class Person2: Drawable {// static static func can also be useddraw() {
        print("Person2 draw")}}Copy the code

mutating

Refer to Swift’s method for mutating

  • Only instance methods in the protocol are marked as mutating
    • Structs and enumerations are allowed to modify their own memory
    • Classes implement methods without mutating. Enumerations and structures need mutating

eg:

protocol Drawable {
    mutating func draw()
}

class Size : Drawable {
    var width: Int = 0
    func draw() {
        width = 10
    }
}

struct Point : Drawable {
    var x: Int = 0
    mutating func draw() {
        x = 10
    }
}
Copy the code

init

  • An initializer init can also be defined in the protocol
    • Non-final class implementations must add required

If you define a class that has subclasses, then the subclass must keep the initializer init, so the keyword required, but if a class is final. There is no need to add required. Classes that are final cannot be inherited by other classes.

For final, see Swift inheritance

Drawable (Drawable); Drawable (Drawable); Drawable (Drawable); Drawable (Drawable); Drawable (Drawable) Because of the keyword final, this class cannot be inherited. So init does not have to be preceded by required

protocol Drawable {
    init(x: Int, y: Int)
}
class Point : Drawable {
    required init(x: Int, y: Int) { }
}
final class Size : Drawable {
    init(x: Int, y: Int) { }
}
Copy the code
  • If the initializer implemented from the protocol happens to override the specified initializer of the parent class
    • The initialization must also be required and override

eg:

protocol Livable {
    init(age: Int)
}

class Person {
    init(age: Int) { }
}

class Student : Person, Livable {
    required override init(age: Int) {
        super.init(age: age)
    }
}
Copy the code

Init, init? And init!

  • Init as defined in the protocol? And init! , you can use init, init? And init! To achieve
  • Init, init! To achieve

eg:

// protocol Livable {init() init? (age: Int) init! (no: Int)} // class Person: Livable {// Init () requiredinit() { } // required init! () {} // All of the following can be implemented as init? (age: Int) required init? (age: Int) { } // required init! (age: Int) {} // Required init(age: Int) {} (no: 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

eg

// Runnable protocol Runnable {func run()} // Runnable protocol Runnable protocol Livable: Runnable { func breath() } class Person : Livable { funcbreath() { }
    func run() {}}Copy the code

Protocol combinations

  • Protocol composition, a combination of multiple protocols, and can contain up to 1 class type

Eg: Two protocols Livable and Runnable, class Person

protocol Livable { } n
protocol Runnable { }
class Person { }
Copy the code

Fn0 is defined below, and the receiving argument must be an instance of Person or its subclasses. Fn1 receiver parameters must follow the Livable protocol instance, the rest can see the code

Func fn0(obj: Person) {} Livable) {} // receive instances of Livable, Runnable protocols func fn2(obj: Livable & Runnable) {} // Accept instances of Livable, Runnable, and Person or a subclass of it func fn3(obj: Person & Livable & Runnable) { } typealias RealPerson = Person & Livable & Runnable // Func fn4(obj: RealPerson) {} Receive instances of Person or subclasses that comply with Livable, Runnable protocolsCopy the code

CaseIterable

  • Making enumerations conform to the CaseIterable protocol allows you to iterate over an enumeration value
CaseIterable enum Season: CaseIterable {caseSpring, summer, autumn, wintercase
let seasons = Season.allCases
print(seasons.count) // 4 // Can be traversedfor season in seasons {
    print(season)
} // spring summer autumn winter
Copy the code

CustomStringConvertible

  • Complies with the CustomStringConvertible protocol, allowing you to customize the printed strings of instances

Eg: The Person class complies with the CustomStringConvertible protocol and can print description internally.

class Person : CustomStringConvertible {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    var description: String {
        "age=\(age), name=\(name)"
    }
}
var p = Person(age: 10, name: "Jack")
print(p) // age=10, name=Jack

Copy the code

Any, AnyObject

  • Swift provides two special types: Any and AnyObject
    • Any: Can represent Any type (enumerations, structs, classes, and even function types)
    • AnyObject: can stand for any class type (write after the protocol: AnyObject means that only the class complies with the protocol)

Eg: STu is of type Any and can be assigned to strings or objects, etc

var stu: Any = 10
stu = "Jack"
stu = Student()
Copy the code

Eg: Create an array that can hold any type

Var data = Array<Any>() var data = [Any]() data.append(1) data.append(3.14) data.append(Student()) data.append("Jack")
data.append({ 10 })
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 perform type casting

Eg: Define the protocol Runnable, class Person and class Student

protocol Runnable { func run() }
class Person { }
class Student : Person, Runnable {
    func run() {
        print("Student run")
    }
    func study() {
        print("Student study")}}Copy the code

When using IS

var stu: Any = 10
print(stu is Int) // true
stu = "Jack"
print(stu is String) // true
stu = Student()
print(stu is Person) // true
print(stu is Student) // true
print(stu is Runnable) // t
Copy the code

With AS, if the conversion fails, none of the subsequent operations are performed. The conversion succeeds before continuing

var stu: Any = 10 (stu as? Student)? .study() // Do not call study stu = Student() (stu as? Student)? .study() // Student study (stu as! Student).study() // Student study (stu as? Runnable)? .run() // Student runCopy the code

X. elf, X. type, and AnyClass

  • X. elf is a pointer to metadata, which holds type-specific information
  • X. elf belongs to x. type
Person class Student: Person {} Person class Student: Person {} Person.Type = Person. Self //stuType Student.Type = Student. Self // Student. Self can be assigned to perType. Anyobject. Type = person. self anyType = student. self public typealias AnyClass = anyobject. Type //anyType2 can be anyType var anyType2: AnyClass = Person.self anyType2 = Student.selfCopy the code

The application of meta-types

Eg :Cat, Dog, Pig, all derived from Animal, we want to initialize them at the same time, using the following code

class Animal { required init() { } }
class Cat : Animal { }
class Dog : Animal { }
class Pig : Animal { }
func create(_ clses: [Animal.Type]) -> [Animal] {
    var arr = [Animal]()
    for cls inClses {// Initialize arr.append(cls.init())}returnArr} // pass Cat,Dog,Pig to initializeprint(create([Cat.self, Dog.self, Pig.self]))
Copy the code

Note that the word required above cannot be omitted

  • In OC, Java, etc., any class eventually inherits from a base class,
  • There is no such rule in Swift. If a class does not inherit from any other class, it is a base class

In fact, is that true? Is it true that there are no classes to inherit?

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
  • You can refer to Swift source code

Self

  • Self is usually used as the return value type, specifying that the return value and the method caller must be of the same type (it can also be used as a parameter type)

Kind of like OC instanType feeling. eg:

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

When calling

Var p = Person() // Print Personprint(p.test()) var stu = Student(print(stu.test())
Copy the code

References:

Swift official source code

From beginner to proficient in Swift programming

More information, welcome to pay attention to the individual public number, not regularly share a variety of technical articles.