这里的var x: Int = 0可以看作是实现了set和get,因为可以赋值和取值;let y: Int = 0由于不能修改值,可以看作只实现了get,也可以使用下图的计算属性方式实现:
为了保证通用,协议中必须用static定义类型方法、类型属性、类型下标
实现的时候使用class则代表方法可以被继承,static则代表方法不能被继承
protocol中不加mutating,而结构体里加了mutating,结构体会报错,protocol对于结构体而言需要加mutating
加required的原因是因为这样可以要求继承自Point的类都必须实现init,从而达到所有遵守Drawable协议的类都实现init,final不需要加是因为加final的类不允许被继承。
如果从协议实现的初始化器,刚好是重写了父类的指定初始化器,那么这个初始化必须同时加required、override
可以看出,遵守Livable协议的Person类必须实现Runnable和Livable都有的方法。
可以给协议组合起别名:
stu属于Any类型,可以赋任何值:
[Any]():创建可以存放任何类型的数组
is判断类型:
as做强制类型转换:
(stu as? Student)?.study():第一个?代表stu可能强制转化为Student,也可能失败,第二个?代表可选类型要调用方法,需要加?
(stu as? Student)!.study() 等同于 (stu as! Student).study()
当确定一定会转换成功用as,否则用as?
Int("123")一定可以转化为Any,所以用as
10一定可以转换为Double,所以用as
对象的指针指向的堆内存的前8个字节存放着类型相关信息,可以把前8个字节认为是元类型的指针,指向元类型metadata
class Person { } var p: Person = Person() var pType: Person.Type = Person.self反汇编上面代码,查看pType存储的到底是什么:
根据两个断点处的rax对比我们可以看出,代表p对象内存地址的第二个rax中的前8个字节与代表pType的第一个rax相同,说明pType存储的是p对象的metadata。
X.self属于X.Type类型由上图看出,由于Student继承自Person,所以pType = Student.self也成立,好比多态的父类指针指向子类对象,但是不继承自Person的类不可以这么写
在Swift底层方法里,有这么个定义代表着AnyClass就是AnyObject.Type,是任意类类型的Type
等价于
type(of: )获取元类型的指针为什么Animal的init(){ }要用required修饰?因为这是要求子类必须有的,实现的方法,万一子类重写init相关的方法,就会造成子类里不会自动继承父类的init,这时添加required,是强制子类实现init()方法,这样就会保证子类可以调用init()方法
class_getInstanceSize:表示对象实际用到的内存大小,也就是存储属性需要的最小值
class_getSuperclass:获取父类,我们可以看到Person虽然没继承任何类,但它有一个要隐藏的基类Swift._SwiftObject
从结果可以看得出来,Swift还有个隐藏的基类:Swift._SwiftObject 可以参考Swift源码:https://github.com/apple/swift/blob/master/stdlib/public/runtime/SwiftObject.hSelf.count 等同于Person.count
Self一般用作返回值类型,限定返回值跟方法调用者必须是同一类型(也可以作为参数类型) protocol Runnable { func test () -> Self } class Person : Runnable { required init() { } func test() -> Self { return type(of: self).init() } } class Student: Person { } var p = Person() //TestSwift.Person print(p.test()) var stu = Student() //TestSwift.Student print(stu.test())