肇鑫的技术博客

业精于勤,荒于嬉

`Self`和`type(of:)`的用法

在讲解Self之前,需要先简短介绍一下type(of:)的用法。

type(of:)

从Xcode 8 beta 6开始,dynamicType被替换为了type(of:)。(SE-0096)

type(of:)的功能是获得实例在运行时(runtime)的元类型(meta type)。这个在之前的Swift里,被称作是dynamicType,与静态的类型进行区别。

Self

Self是一个特殊的类型。它是self对应的类型。而self是动态类型。比如:

class Foo {
    func printType() {
        print(type(of:self))
    }
    
    func printSelf() {
        print(self)
    }
}

class Bar:Foo {
    
}

let foo = Foo()
foo.printType() // Foo
foo.printSelf() // Foo

let bar = Bar()
bar.printType() // Bar
bar.printSelf() // Bar

var test = Foo()
test.printType() // Foo
test.printSelf() // Foo

test = Bar()
test.printType() // Bar
test.printSelf() // Bar

可以看到,self始终对应的是实际类型,无论变量的类型是Foo还是Bar。

由于这个特性的存在,这使得Self无法从静态类型进行转换,而只能通过self来生成。即:

class Foo {
    func bar() -> Self {
        return self
    }
}

class Foo1 {
    func bar1() -> Self {
        return type(of:self).init()
    }
    
    required init() { }
}

注意

Foo1中,有一个required init(),这是type(of:self).init()必须的。

Self的使用有以下方式:

1. 在协议的返回值中使用

这是最常见的使用方式。

protocol Foo {
    func instance() -> Self
}

class Bar: Foo {
    func instance() -> Self {
        return self // Declaration: let `self`: Self
    }
    func other() {
        let i = self // Declaration: let `self`: Bar
    }
}

class otherBar:Foo {
    func instance() -> Self {
        return type(of:self).init()
    }
    
    required init() { }
}

注意

Bar中的实现协议的函数里,self是Self类型。而非Self返回值的函数里,self是所在类的类型。
可以使用type(of:self).init(),获得一个新的Self实例。此时,类中必须要有一个required init()
Self作为函数的返回值的类型时,可以直接写在类中,而不必非要有协议。
下面2和3中的情形,使用associateType的效果,要好于Self。因此,1是Self的最常用的方式。


2. 在协议的函数的参数类型中使用

protocol Foo {
    func bar(b:Self)
}

class Bar:Foo {
    func bar(b:Bar) {
        print(b)
    }
}

注意

Bar中的func bar(b:Bar)是Bar而不是Self。但是这满足协议。这也符合类的多态,即Bar的子类可以调用这个函数。


3. 在协议的属性里使用

protocol Foo {
    var bar:Self { get set }
}

final class Bar:Foo {
    var bar: Bar
    
    init(b:Bar) {
        self.bar = b
    }
}

注意

在协议的属性里使用Self时,类必须时final类。


参考文献:

以下参考文献的一些代码针对的是3.0版本之前的Swift。部分内容需要修正才能运行。但基本原理是相同的。

Types and meta types in swift
Swift中你应该知道的一些有用的tips
Generic Protocols & Their Shortcomings 这篇难度较高,慎看。
Self in Protocol and class method