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

时间:2015-07-15 18:32:34

标签: swift

Swift中元词类型.Type.self之间有什么区别?

.self.Type是否会返回struct

我了解.self可用于检查dynamicType。你如何使用.Type

5 个答案:

答案 0 :(得分:31)

这是一个简单的例子:

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

假设每个实体由两件事代表:

  • 输入:# entitiy name #

  • 元节类型:# entity name # .Type

  

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

     

Source.

您可以快速注意到这是递归的,可以使用(((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

.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 { ... }

答案 1 :(得分:21)

在哪里使用?

如果您正在编写/创建一个接受类型的函数,例如UIView.Type一个实例,例如UIView()然后你会写T.Type作为参数的类型。它作为参数的期望可以是:String.selfCustomTableView.selfsomeOtherClass.self

但为什么函数需要一个类型?

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

    来自tableview的
  1. register函数
  2. tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
    

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

      来自decode
    1. JSONDecoder函数。示例来自链接
    2. CustomTableViewCell

      注意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) 。因为您传递了try decoder.decode(GroceryProduct.self, from: json),所以它知道它需要实例化GroceryProduct.self类型的对象。如果它不能那么就会抛出错误

      1. 作为需要类型的替代解决方法,请参阅以下问题:Swift can't infer generic type when generic type is being passed through a parameter。接受的答案提供了一个有趣的选择。
      2. 有关内部及其工作原理的更多信息:

        。键入

          

        类,结构或枚举类型的元类型是其名称   该类型后跟.Type。协议类型的元类型 - 不是   在运行时符合协议的具体类型是名称   该协议后跟.Protocol。例如,元的类型   类型GroceryProductSomeClass,其元类型为。{1}}   协议 SomeClass.TypeSomeProtocol

             

        来自Apple:metaType Type

        Under the hood SomeProtocol.Protocol

        AnyClass

        基本上,您会看到typealias AnyClass = AnyObject.Type // which is why you see T.Type AnyClassAny.Type,因为它需要某种类型。我们看到的一个非常常见的地方是,当我们想要使用AnyObject.Type func 为我们的tableView注册类时。

        register

        如果您对Swift的内容感到困惑。&#39;然后执行上面的操作,然后查看here

        中的评论

        上述内容也可以写成:

        func register(_ cellClass: Swift.AnyClass?, forCellReuseIdentifier identifier: String)
        

        .self

          

        您可以使用 postfix 自我表达式将类型作为值进行访问。   例如,SomeClass.self返回SomeClass本身,一个实例   SomeClass。 SomeProtocol.self返回SomeProtocol本身,   在运行时符合SomeProtocol的类型的实例。您   可以使用类型(of :)表达式来访问类型的实例   该实例的动态,运行时类型为值,如下所示   示例显示:

             

        来自Apple:metaType Type

        游乐场代码:

        简单示例

        func register(_ cellClass: AnyObject.Type, forCellReuseIdentifier identifier: String)
        

        硬例

        struct Something {
            var x = 5
        }
        
        let a = Something()
        type(of:a) == Something.self // true
        

        我强烈建议您阅读 Apple documentation on Types。另请参阅here

答案 2 :(得分:13)

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

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

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

答案 3 :(得分:2)

这是今天让我感到困惑的那些话题之一。

我正在编写一个通用函数:

func foo<T: Protocol>(ofType: T.Type) {
    T.bar()
}

并尝试按以下方式调用它:

foo(ofType: ClassImplementingProtocol.Type) // Compiler error

花了大约30分钟研究它为什么不起作用。然后我尝试了这个:

foo(ofType: ClassImplementingProtocol.self) // Works

结果发现Xcode的代码完成非常不好表现出元数据类型和类型之间的区别...从代码完成弹出窗口中,.self和.Type看起来是一样的东西:

enter image description here

但是它的“类似于im 5的解释”是,当您具有Class.Type的方法参数时,它期望的是Class.Type的实例。

Class.self返回Class.Type的实例,而Class.Type则引用Class.Type ...

很不清楚你是否问我。

答案 4 :(得分:0)

元类型.Type

Metatype 是一种类型,它允许您访问类和结构的部分[About] 类型(不是实例),如初始化器class 和 static[About] 属性和方法

let var1: String = HelloWorld
let var2: String.Type = HelloWorld.self

一些实验:

class SomeClass {
    required init() { }
    
    class func foo1() { }
    static func foo2() { }
    
    func foo3() { }
}

class SomeSubClass: SomeClass { }
let a1: SomeClass = SomeClass()
let a2: SomeClass = a1
let a3: SomeClass = a1.self

SomeClass.self.foo1() //class func
SomeClass.foo1() //class func

//static. metatype by type(class name) <class_name/structure_name>.self
let c1: SomeClass.Type = SomeClass.self
//dynamic. metatype by instance
let c2: SomeClass.Type = type(of: a1)

//access to type's init, class, static throught Metatype
let d1: SomeClass = c1.self.init()
let d2: SomeClass = c1.init()

//call
c1.foo1() //class func
c1.foo2() //static func
//        c1.foo3() //instance func. Instance member 'foo3' cannot be used on type 'SomeClass'
//        c1.foo3(SomeClass()) //Expression resolves to an unused function

//Sub
// <class_name>.Type allows to save class and sunclass
var e1: SomeClass.Type = SomeClass.self //class
e1 = SomeSubClass.self //sub class

//Any.Type allows to save class and struct
var e2: Any.Type = SomeClass.self //class
e2 = String.self //struct

//AnyObject.Type allows to save only class
var e3: AnyObject.Type = SomeClass.self //class
e3 = NSString.self //class

获取字符串

let typeString = "\(SomeType.Type)"

func register<T>(instance: T) {
    instanceString = String(describing: type(of: instance))
}