Any,AnyObject,AnyClass ,元类型,和.self

Any和AnyObject是swift中两个产物,很容易让人迷惑,在swift官方中:

  • AnyObject可以代表任何class类型的实例
  • Any可以表示任意类型,甚至包括方法(func)类型

Any,AnyObject

AnyObject 的由来

写过Objective-C的读者都知道Objective-C有一个叫做id的神奇东西。

编译器不会对声明为id的变量进行类型检查,它可以表示任意类型的实例。

在Cocoa框架中很对地方都使用了id来进行像参数传递和方法返回这样的工作,这是Objectice-C动态特性的一种表现。现在Swift最主要的用途是使用Cocoa框架进行app开发,因此为了与Cocoa框架协作,使用了一种类似的,可以代表任意class类型的AnyObject来代替原来id的概念

Any,AnyObject 的本质区别

  1. 在swift编译器不仅不会对AnyObject实例方法调用做出检查,甚至对于AnyObject的所有方法返回Optional的结果。

这个虽然符合Objective-C中的理念,但是在Swift环境下使用起来就非常麻烦,也很危险。应该选择的做法是在使用时先确定AnyObject真正的类型并进行转换后在进行调用。

假设原来的API返回的是一个id,那么在Swift中被映射为AnyObject?(因为id是可以指向nil的,所以在这里我们需要一个Optional的版本),虽然调用应该是没问题的,但是我们最好这样写:

func someMethod() -> AnyObject?{
// ...
//返回一个AnyObject?,等价于在Objective-C中返回一个id
return result
}

let anyObject: AnyObject?= SomeClass.someMethod
if let someInstance = anyObject as? SomeRealClass {
// 拿到具体的 SomeRealClass的实例
someInstance.funcOfSomeRealClass()
}

AnyObject 的定义,它其实就是一个接口:

protocol  AnyObject {
}

所有的class都隐式的实现了这个接口,这也是AnyObject只适用于class的原因。而在swift 中所有的基本数据类型(Int、Double、Float、String、Array、和 Dictionary),全部都是struct类型,因此苹果又提出的Any

前言

在Swift中能表示“任意”这个概念的除了Any和AnyObject以外还有AnyClass 。AnyClass 在Swift 中被一个typealias所定义:

typealias AnyClass  = AnyObject.Type

通过AnyObject.Type这种方式所的到的是一个元类型(Meta)。在声明时我们总是在类型的名称后面加上.type,比如A.Type 代表的是A类型的类型。也就是说,我们可以声明一个元类型来存储A这个类型本身,从而A中取出其类型时,我们需要用到.self:

class A {
    
}

let typeA: A.Type = A.self

在swift中,.self的作用

  • .self 可以用在类型后面取得类型本身
  • 也可以用在某个实例后面取得这个实例本身

在了解这个基础之后,我们就明白AnyObject.type ,或者说AnyClass所表达的东西其实并没有什么奇怪的,它就是任意类型的本身。所以,对于上面A的类型的取值,我们也可以强制让它是一个AnyClass:

class A {
    
}

let typeA: AnyClass = A.self

这样,要是A中有一个类方法,我们就可以通过 typeA来调用了:

class A {
    class func method() {
      print("Hello")
    }
}

let typeA: A.Type = A.self
typeA.method()

// 或者
let anyClass:AnyClass = A.self
(anyClass as A.Type).method()

这样做得意义,难道不是直接使用A.method()来调用吗??没错对于独立的类型来说完全没有必要关心元类型,但是元类型或者元编程的概念可以变得非常灵活和强大,在这我们编写某些框架性的代码会非常方便。

比如我们想要传递一些类型的时候,就不需要不断地去改动代码了

下面的例子中虽然我们是用代码声明的方式获取了MusicViewController 和AlbumViewController的元类型,但是这一步完全可以通过读入配置文件之类的方式来完成。而在将这些元类型存入数组并且传给别的方法来配置这一点上,元类型编程就很难被替代了

class MusicViewController: UIViewController { 
}
class AlbumViewController: UIViewController { 
}
let userimgVCTypes: [AnyClass] = [MusicViewController.self, 
AlbumViewController.self]

func setupViewControllers(_ vcTypes: [AnyClass]){
for vcType in vcTypes {
if vcType is UIViewController.Type {
let vcClass = vcType as! UIViewController.Type  // 获取类
let vc = vcClass.init()                        // 获取类实例对象
print(vc)

}

}

}

setupViewControllers(userimgVCTypes)

这么一来,我们完全可以搭好框架,然后用DSL的方式进行配置,就可以在不触及swift编码的情况下,很简单地完成一系列复杂的操作了。

另外在Cocoa AP 中我们也经常遇到需要输入一个AnyClass 的情况,这时候我们也应该使用 .self 的方式来获取所需的元类型,例如在tableView的cell的类型的时候:

tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")

.Type 表示的是某个类型的元类型,而在swift中,除了class,struct和enum这三个类型,我们还可以定义protocol.对于protocol来说,有时候我们也会想取得接口的元类型。这时我们可以在某个protocol的名字后面使用.protocol来获取,使用的方法和.Type类似的。

你可能感兴趣的:(#,Swift开发必备Tip,AnyClass,AnyObject,Any)