Swift - metatype .Type和.self之间有什么区别?

Boo*_*oon 51 swift

metatype .Type.selfSwift有什么区别?

.self.Type返回struct

我明白.self可以用来检查dynamicType.你怎么用的.Type

Dev*_*ist 38

这是一个简单的例子:

func printType<T>(of type: T.Type) {
    // or you could do "\(T.self)" directly and
    // replace `type` parameter with an underscore
    print("\(type)") 
} 

printType(of: Int.self) // this should print Swift.Int


func printInstanceDescription<T>(of instance: T) {
    print("\(instance)")
} 

printInstanceDescription(of: 42) // this should print 42
Run Code Online (Sandbox Code Playgroud)

假设每个实体由两个部分代表:

  • 类型: # entitiy name #

  • 元类型: # entity name # .Type

元类型类型是指任何类型的类型,包括类类型,结构类型,枚举类型和协议类型.

资源.

您可以快速注意到这是递归的,并且可以按类型等(((T.Type).Type).Type)进行.

.Type 返回元类型的实例.

我们有两种方法可以获得元类型的实例:

  • 调用.self一个具体的类型Int.self,它将创建一个 静态元类型实例Int.Type.

  • 从任何实例获取动态元类型实例 type(of: someInstance).

危险区域:

struct S {}
protocol P {}

print("\(type(of: S.self))")      // S.Type
print("\(type(of: S.Type.self))") // S.Type.Type
print("\(type(of: P.self))")      // P.Protocol
print("\(type(of: P.Type.self))") // P.Type.Protocol
Run Code Online (Sandbox Code Playgroud)

.Protocol是另一种仅在协议背景下存在的元类型.也就是说,我们没有办法表达我们想要的东西P.Type.这可以防止所有通用算法使用协议元类型,并可能导致运行时崩溃.

对于更好奇的人:

type(of:)函数实际上是由编译器处理的,因为.Protocol创建了不一致.

// This implementation is never used, since calls to `Swift.type(of:)` are
// resolved as a special case by the type checker.
public func type<T, Metatype>(of value: T) -> Metatype { ... }
Run Code Online (Sandbox Code Playgroud)

  • 不客气:)还有一个`.dynamicType`.这个是在运行时获取实例的最后一级类型.让我们说你有这个:`让实例:UIView = CustomUIView()`然后你会在某处调用`instance.dynamicType`然后你会得到`CustomUIView`而不是`UIView`.;) (3认同)

Hon*_*ney 27

在哪里使用?

如果您正在编写/创建一个接受类型的函数,例如UIView.Type,不是实例,UIView()那么您将编写T.Type为参数的类型.预计什么作为参数可以是:String.self,CustomTableView.self,someOtherClass.self.

但为什么一个功能需要一个类型?

通常,需要类型的函数是为您实例化对象的函数.我可以想到两个很好的例子:

  1. 从tableview 注册函数
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
Run Code Online (Sandbox Code Playgroud)

请注意,你通过了CustomTableViewCell.self.如果稍后您尝试将类型的tableView出列CustomTableViewCell但未注册CustomTableViewCell类型,那么它将崩溃,因为tableView尚未出列/实例化任何CustomTableViewCell类型的tableviewcells .

  1. 来自JSONDecoder的解码函数.示例来自链接
struct GroceryProduct: Codable {
    var name: String
    var points: Int
    var description: String?
}

let json = """
{
    "name": "Durian",
    "points": 600,
    "description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)

print(product.name)
Run Code Online (Sandbox Code Playgroud)

注意事项try decoder.decode(GroceryProduct.self, from: json).因为你传递GroceryProduct.self它知道它需要实例化一个类型的对象GroceryProduct.如果它不能那么它会抛出错误

  1. 作为需要类型的替代解决方法,请参阅以下问题:当通用类型通过参数传递时,Swift无法推断泛型类型.接受的答案提供了一个有趣的选择.

更多关于内部及其工作原理:

.类型

类,结构或枚举类型的元类型是该类型的名称,后跟.Type.协议类型的元类型 - 不是在运行时符合协议的具体类型 - 是该协议的名称,后跟.Protocol.例如,的元类型 的类类型SomeClassSomeClass.Type与所述的元类型 的协议 SomeProtocolSomeProtocol.Protocol.

来自Apple:metaType Type

引擎盖下 AnyClass

typealias AnyClass = AnyObject.Type // which is why you see T.Type 
Run Code Online (Sandbox Code Playgroud)

基本上,你在哪里都看到AnyClass,Any.Type,AnyObject.Type,其因为它需要的类型.我们看到的一个非常常见的地方是我们想要使用func 为tableView 注册一个类register.

func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)
Run Code Online (Sandbox Code Playgroud)

如果你对"斯威夫特"的含义感到困惑.在上面做,然后看到这里的评论

以上内容也可以写成:

func register(_ cellClass: AnyObject.Type, forCellReuseIdentifier identifier: String)
Run Code Online (Sandbox Code Playgroud)

.自

您可以使用后缀自表达式将类型作为值进行访问.例如,SomeClass.self返回SomeClass本身,而不是 SomeClass的实例.SomeProtocol.self返回SomeProtocol本身,而不是 在运行时符合SomeProtocol的类型的实例.您可以将类型(of :)表达式与类型实例一起使用,以将该实例的动态,运行时类型作为值进行访问,如以下示例所示:

来自Apple:metaType Type


游乐场代码:

简单的例子

struct Something {
    var x = 5
}

let a = Something()
type(of:a) == Something.self // true
Run Code Online (Sandbox Code Playgroud)

很难的例子

class BaseClass {
    class func printClassName() {
        print("BaseClass")
    }
}
class SubClass: BaseClass {
    override class func printClassName() {
        print("SubClass")
    }
}


let someInstance: BaseClass = SubClass()
/*                      |                |
                    compileTime       Runtime
                        |                | 
To extract, use:       .self          type(of)

  Check the runtime type of someInstance use `type(of:)`: */

print(type(of: someInstance) == SubClass.self) // True
print(type(of: someInstance) == BaseClass.self) // False

 /* Check the compile time type of someInstance use `is`: */

print(someInstance is SubClass) // True
print(someInstance is BaseClass) // True
Run Code Online (Sandbox Code Playgroud)

我强烈建议您阅读有关类型的Apple文档.另见这里


new*_*cct 15

它们在语法上出现在不同的地方.

在语法上你必须指定类型的地方,Something.Type是一个有效的类型,对应于元类型(类的元类)的类型Something.Something.self不是类型的有效语法.

在语法上你必须编写表达式的地方,Something.self是一个有效的表达式.它是类型的表达式,Something.Type值是表示类型的事物(在类的情况下为"类对象")Something.Something.Type不是有效的表达式语法.


归档时间:

查看次数:

11901 次

最近记录:

6 年,10 月 前