协议与继承¶
class定义了对象是什么
protocol定义了对象有哪些(共同)行为 ,并通过 extension
的方式来对我们的类进行扩展。
//CustomStringConvertible是debug下的一个协议属性
class LGTeacherP{
var age = 10
var name = "Kody"
func debug(){
print(".....")
}
}
class Dog{
var name = "糯米"
var type = "白梗"
func debug(){
print(".....")
}
}
extension LGTeacherP: CustomStringConvertible{
var description: String { get { return "LGTeacher: \(age)\(name)"}}
}
extension Dog: CustomStringConvertible{
var description: String { get { return "Dog: \(name)\(type)"}}
}
func print(subject: CustomStringConvertible) {//subject遵循CustomStringConvertible协议
let string = subject.description
print(string)
//to do...
}
func test() {
print(subject: LGTeacherP())
}
协议中定义属性¶
协议要求属性必须明确是 get
或 get
和 set
protocol HHProtocol{
var age: Int{ get set }
var name: String{ get }
}
//需要注意的一点是:并不是说当前声明 get 的属性一定是计算属性
class HHTeacherP: HHProtocol{
var age: Int = 18
var name: String//name可以是存储属性
init(_ name: String) {
self.name = name
}
}
协议中的异变方法¶
表示在该方法可以改变其所属的实例,以及该实例的所有属性(用于枚举和结构体),在为类实现该方法的时候不需要写 mutating 关键字。
枚举和结构体协议中的方法需要mutating,类不需要mutating。
protocol Togglable {
mutating func toggle()
}
协议中定义初始化器¶
类在实现协议中的初始化器必须使用 required 关键字修饰初始化器,表明所有该类的子类都必须实现该初始化器。
protocol HHClassProtocol {
init(_ age: Int)
}
class HHTe: HHClassProtocol{
var age = 10
required init(_ age: Int) {//必须加require关键字
self.age = age
}
}
//final不允许继承,就可以不加require关键字
final class HHTeF: HHClassProtocol{
var age = 10
init(_ age: Int) {
self.age = age
}
}
类专用协议¶
通过添加 AnyObject 关键字到协议的继承列表,就可以限制协议只能被类类型采纳。这样才delegate属性可以用weak修饰。
protocol MyProtocol: AnyObject{}
可选协议¶
如果不想强制让遵循协议的类类型实现,可以使用 optional 作为前缀放在协议的定义。
@objc protocol IncrementableO{
@objc optional func increment(by: Int)
}
class HHTeaO: IncrementableO{
}
func testO() {
let t:IncrementableO = HHTeaO()
t.increment?(by: 10)
}
协议和继承¶
protocol Incrementable{
// func increment(by: Int)
}
extension Incrementable{
func increment(by: Int) {
print("协议extension实现")
}
}
class HHTea: Incrementable{
//PWT
func increment(by: Int) {
print("HHTea协议实现")
}
}
class SubHHTea: HHTea{
//子类没有实现协议方法,没有协议见证表
}
func test2() {
let t:Incrementable = SubHHTea()
t.increment(by: 10)//执行的是HHTea的increment方法 如果protocol Incrementable没有定义increment方法,那么执行的是extension Incrementable的increment方法
}
协议原理探究¶
// MARK: 案例
protocol Shape{
var area: Double{
get
}
}
//前16字节加8字节 = 24
class Circle: Shape{
var radious: Double
init(_ radious: Double) {
self.radious = radious
}
var area: Double{
get{
return radious * radious * 3.14
}
}
}
func testShape() {
let circle: Circle = Circle.init(10.0)
print(class_getInstanceSize(Circle.self))
print(MemoryLayout.size(ofValue: circle))//打印8
var circle1: Shape = Circle.init(10.0)
print(MemoryLayout.size(ofValue: circle1))//打印40
withUnsafePointer(to: &circle1) { ptr in
ptr.withMemoryRebound(to: HHProtocolBox.self, capacity: 1) { pointer in
print(pointer.pointee)
let descPtr = pointer.pointee.witness_table.pointee.protocol_conformance_descriptor.pointee.protocolDesc.getmeasureRelativeOffset()
print(String(cString: descPtr.pointee.Name.getmeasureRelativeOffset()))
print(pointer.pointee.witness_table.pointee.witnessMethod)
print("end")
}
}
}
// MARK: protocol底层结构体
//Existential Container 是编译器生成的一种特殊的数据类型,用于管理遵守了相同协议的协议类型,因为这些类型的内存大小不一致,所以通过当前的 Existential Container 统一管理
struct HHProtocolBox{
var heapObject: UnsafeRawPointer
var unknow1: UnsafeRawPointer
var unknow2: UnsafeRawPointer
var metadata: UnsafeRawPointer
var witness_table: UnsafeMutablePointer<TargetWitnessTable>
}
//
struct TargetWitnessTable{
var protocol_conformance_descriptor: UnsafeMutablePointer<TargetProtocolConformanceDescriptor>
var witnessMethod: UnsafeRawPointer
}
struct TargetProtocolConformanceDescriptor{
var protocolDesc: TargetRelativeDirectPointer<TargetProtocolDescriptor>
var typeRef: UnsafeRawPointer
var witnessTablePattern: UnsafeRawPointer
var flags: UInt32
}
struct TargetProtocolDescriptor{
var flags: UInt32
var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
var Name: TargetRelativeDirectPointer<CChar>
var NumRequirementsInSignature: UInt32
var NumRequirements: UInt32
var AssociatedTypeNames: TargetRelativeDirectPointer<CChar>
}
// 还原TargetRelativeDirectPointer
// 相对地址信息
struct TargetRelativeDirectPointer<Pointee>{
var offset: Int32
mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {
let offset = self.offset
return withUnsafePointer(to: &self) { p in
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
}
}
}
- 每个遵守了协议的类,都会有自己的PWT,遵守的协议越多,PWT中存储的函数地址就越多
- PWT的本质是一个指针数组,第一个元素存储TargetProtocolConformanceDescriptor,其后面存储的是函数地址
- PWT的数量与协议数量一致
- Existential Container 是编译器生成的一种特殊的数据类型,用于管理遵守了相同协议的协议类型,因为这些类型的内存大小不一致,所以通过当前的 Existential Container 统一管理
- 对于小容量的数据,直接存储在 Value Buffer
- 对于大容量的数据,通过堆区分配,存储堆空间的地址
witness-table
协议见证表protocol with table¶
类遵循了协议,实现了方法,编译器就会为类创建witness-table,记录类实现方法的编码信息。为每一个遵循协议的类创建witness-table。
两个类继承一个协议,两个协议见证表。
类遵循两个协议,PWT有两个。遵循的协议中的方法越多,PWT中的函数就越多。
NSObjectProtocol¶
Protocol继承NSObjectProtocol,才可以判断
delegate?.responds(to: #selector(<#T##@objc method#>))
@objc protocol HHGroupShadowTableViewDelegate: NSObjectProtocol {
func groupShadowTableView(_ tableView: HHGroupShadowTableView, heightForFooterInSection section: Int) -> CGFloat
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if let delegate = self.groupShadowDelegate, delegate.responds(to: #selector(HHGroupShadowTableViewDelegate.groupShadowTableView(_:heightForFooterInSection:))) {
return delegate.groupShadowTableView(self, heightForFooterInSection: section)
}
return 0.0
}