swift中围绕元类型实例metadata和元类型的一些特性
AnyObject
- 代表任意类的实例
- 代表类的类型
- 代表类遵守的协议
具体用法
请看上面代码,LGTeacher是值类型,不是引用类型,所以上面的AnyObject用法都是错误的
正确用法,将LGTeacher改为class就可以
class LGTeacher: MyProtocol {
var age = 18
}
var t = LGTeacher()
var t1: AnyObject = t.self //任意类的实例
var t2: AnyObject = LGTeacher.self //任意类的类型
var t3: LGTeacher = t2 as LGTeacher
protocol MyProtocol: AnyObject { //类遵循的协议
}
//这样的转换也是允许的
var p:MyProtocol = LGTeacher()
var o:AnyObject = p
AnyObject与具体类型的转换
我们在开发过程中,有时候不知道实例具体的类型,可以用AnyObject代替, 如果知道了类型,可以使用 as as?as!来将AnyObject做类型转换
oc交互的时候的使用
在swift和oc交互的时候,也经常使用AnyObject来做某种类型的instance
例如:
var age:AnyObject = t.age as NSNumber
self
用法
- 当T是任意类的实例,.self返回任意实例本身
- 当T是类的类型,.self返回任意类的类型,也就是元类型, 就是前面我们提到的metaData
上面的代码,打印t1, t2,以及相关内存格式化:
这就证明了我们上面的说法。
self在方法中的不同表现
class LGTeacher{
var age = 18
func test(){
//当前实例对象
let t = self
print(self)
}
static func test1(){
// self 是 LGTeacher 这个类型本身
let t = self
print(self)
}
}
var t = LGTeacher()
t.test()
LGTeacher.test1()
///
(lldb) po t
<LGTeacher: 0x100705bc0>
(lldb) x/8g 0x100705bc0
0x100705bc0: 0x000000010000c268 0x0000000400000003
0x100705bd0: 0x0000000000000012 0x00007ff82ed45a18
0x100705be0: 0x0000000000000000 0x0000000000000000
0x100705bf0: 0x00007ff8524f0002 0x00027ff82ed460c8
LGSwiftTest.LGTeacher
(lldb) po t
LGSwiftTest.LGTeacher
上面打印输出,说明
- 实例方法中的self。代表的就是当前实例。
- 类方法中的self。代表的就是当前类的类型本身,即metadata。
我们看看汇编中的信息:
上面汇编代码也能证实,我们两个方法中self的意义。
小写self我们研究过了,那么大写Self呢?
Self
Self不是特定类型,而是让您方便引用当前类型,而无需重复或知道当前类型的名称。
用法
- 在协议或协议成员声明中,Self是指最终符合协议的类型
- 方法的返回值
- 只读下标的返回类型
- 只读计算属性的类型
- 可以理解为一个代表当前的Covariant类型
看如下代码:
class LGTeacher {
static var age = 18
let age1 = age
var age2 = age
lazy var age3 = Self.age
var age4: Int {
return Self.age
}
var age5: Int {
return LGTeacher.age
}
func test() -> Self {
//当前实例对象
return self
}
}
protocol MyProtocol {
func get() -> Self
func set(value: Self)
}
extension LGTeacher: MyProtocol {
func get() -> Self {
return self
}
func set(value: LGTeacher) {
let t = value.self
print(value)
print(t)
}
}
Any
代表任意类型,包括 function类型或者 Optional类型
与OC中id类型类似
它与AnyObject有本质区别,AnyObject只能代表类类型实例。
例如:
AnyClass
代表任意实例的元类的类型
public typealias AnyClass = AnyObject.Type
X.Type
X.self 也是有自己的类型的,就是X.Type,就是元类型的类型。
注意,这里我们就得出了结论,任意metadata实例,都可以用AnyClass定义, AnyClass = AnyObject.Type = X.Type
打印和汇编分析
上面的打印结果,以及汇编注解都证实我们的理论。
动态类型(dynamic type)和静态类型(static type)
- 静态类型:是在编译时就确定的类型
- 动态类型:是在运行时才能确定的类型
func test(_ value:Any) {
var ret:Any = type(of: value)
print(ret)
}
func test1(_ value:AnyObject) {
var ret:AnyClass = type(of: value)
print(ret)
}
test(100.0)
test(100)
test1(LGTeacher())
test1(LGPerson())
print("-----end")
///result
Double
Int
LGTeacher
LGPerson
看上面代码: 对于test和test1中的value来说,Any和AnyObject是编译器知道的编译完成的类型,所以叫静态类型,而我们实际运行调用的时候,value的类型是不确定的,这时候通过type(of: )获取的就是他的运行时类型,也就是动态类型。
type(of: )
获取的就是一个值的动态类型。
看上面代码,可以看到,协议类型是不能用AnyObject来代替的。
使用Any代替以后,发现答应结果,type(of: )不是TeachProtocol
使用泛型才实现我们的需求。
所以我个人认为,泛型 比 Any要更广,没研究源码。大家有兴趣研究一下。