阅读 234

Swift系列十七 - 任意类型

任意类型、泛型、强制类型转换在开发中也是经常用到。

一、Any、AnyObject

Swift提供了2种特殊的类型:AnyAnyObject

Any: 可以代表任意类型(枚举、结构体、类,也包括函数类型)

AnyObject: 可以代表任意类型(在协议后面写上:AnyObject代表只有类能遵守这个协议)

示例代码一:

class Person { }
var p: Any = 10
p = "idbeny"
p = Person()
复制代码

如果变量p后面是具体类型或不写类型就不能编译通过。

示例代码二(存放任意类型的数组):

var data = Array<Any>()
// 数组的另外一种写法
// var data = [Any]()
data.append(1)
data.append(1.01)
data.append(Person())
data.append("idbeny")
data.append({ 10 })
复制代码

示例代码三:

protocol Runnable: AnyObject { }
class Person: Runnable {
    
}
复制代码
  • 如果上面的示例代码三使用struct

  • 改用Any即可正常使用:
    protocol Runnable: Any { }
    struct Person: Runnable {
        
    }
    复制代码

二、is、as?、as!、as

is用来判断是否为某种类型,as用来做强制类型转换。

示例代码一(is的使用):

protocol Runnable {
    func run()
}
class Person { }
class Student: Person, Runnable {
    func run() {
        print("Student run")
    }
    func study() {
        print("Student study")
    }
}
var stu: Any = 10
print(stu is Int) // 输出:true
print(stu is Double) // 输出:false

stu = "idbeny"
print(stu is String) // 输出:true

stu = Student()
print(stu is Person) // 输出:true
print(stu is Student) // 输出:true
print(stu is Runnable) // 输出:true
复制代码

示例代码二(as的使用):

(stu as? Student)?.study() // 没有输出

stu = Student()
(stu as? Student)?.study() // 输出:Student study
(stu as! Student).study() // 输出:Student study
(stu as? Student)?.run() // 输出:Student run
复制代码
  • as?:转换为可选类型
  • as!:强制转换类型(失败后会报错)
  • as:一定能够强制转换成功的时候使用。

as的应用场景一:

var data = [Any]()
data.append(Int("123") as Any)
复制代码

as的应用场景二:

var d = 10 as Double
print(d) // 输出:10.0
复制代码

三、X.self、X.Type、AnyClass

X.self是一个元类型(metadata)的指针,metadata存放着类型相关信息。AnyClassAnyObject.Type类型,表示任意元类型。

示例代码一: X.self属于X.Type类型。Person.self类似于OC中的Person.class

class Person {

}
var p = Person()
var pType: Person.Type = Person.self
复制代码

汇编分析:

Person.self代表的是指针p指向的实例对象在堆空间存放的前8个字节(元类型信息地址)。

示例代码二:

class Person { }
class Student: Person { }
var perType: Person.Type = Person.self
var stuType: Student.Type = Student.self
perType = Student.self

var anyType: AnyObject.Type = Person.self
anyType = Student.self

public typealias AnyClass = AnyObject.Type
var anyType2: AnyClass = Person.self
anyType2 = Student.self
复制代码

上面的代码简单描述就是:父类指针可以指向子类实例。

示例代码三:

var per = Person()
print(Person.self == type(of: per)) // 输出:true
复制代码

type(of: per)本质就是把对象的前8个字节取出来。

四、元类型的应用

示例代码一:

class Animal {
    required init() { }
}
class Cat: Animal { }
class Dog: Animal { }
class Pig: Animal { }
func create(_ clses: [Animal.Type]) -> [Animal] {
    var arr = [Animal]()
    for cls in clses {
        arr.append(cls.init())
    }
    return arr
}
print(create([Cat.self, Dog.self, Pig.self]))
复制代码

Animal()Animal.self.init()效果一致。类似OC中[[Animal.class alloc] init]

上面代码中基类Animal的初始化方法加了required,为什么呢? 因为子类初始化器必须实现父类的初始化器,否则有可能找不到init方法导致程序崩溃。

示例代码二: Swift支持部分runtime函数。

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)!) // 输出:_TtCs12_SwiftObject
复制代码

从结果可以看出来,Swift还有个隐藏的基类:Swift.SwiftObject

可以参考Swift源码:github.com/apple/swift…

五、Self

  1. Self代表当前类型。

示例代码:

class Person {
    var age = 1
    static var count = 2
    func run() {
        print(self.age) // 输出:1
        print(Self.count) // 输出:2
    }
}
var p = Person()
p.run()
复制代码
  1. Self一般用作返回值类型(也可以作为参数类型),限定返回值跟方法调用者必须是同一类型。类似于OC中的instancetype

示例代码:

protocol Runnable {
    func test() -> Self
}
class Person: Runnable {
    required init() { }
    func test() -> Self {
        type(of: self).init()
    }
}
class Student: Person {
    
}
var p = Person()
p.test()

var stu = Student()
stu.test()
复制代码

结果:谁调用就返回谁的实例。

更多系列文章,请关注微信公众号【1024星球】。

文章分类
iOS
文章标签