What is the difference between the .Type and .self metatypes?

What is the difference between the .Type and .self in Swift?

Do .self and .Type return a struct ?

I understand that .self can be used to check with dynamicType . How do you use .Type ?

+37
swift
Jul 15 '15 at 18:32
source share
3 answers

Here is a quick example:

 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 

Suppose each entity is represented by two things:

  • Type: # entitiy name #

  • Metatype: # entity name #.Type

A metatype type refers to a type of any type, including class types, structure types, enumeration types, and protocol types.

Source.

You can quickly notice that this is recursive and can be done using types such as (((T.Type).Type).Type) and so on.

.Type returns a metatype instance.

There are two ways to get a metatype instance:

  • Call .self for a specific type, such as Int.self that will create a static instance of Int.Type .

  • Get an instance of a dynamic metatype from any instance via type(of: someInstance) .

Dangerous zone:

 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 is another metatype that exists only in the context of protocols. However, there is no way we can express that we want only P.Type . This prevents all common algorithms from working with protocol metatypes and can lead to runtime crashes.

For more curious people:

The type(of:) function is actually handled by the compiler due to a mismatch, .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 { ... } 
+27
Jul 15 '15 at 19:53
source share

Where is it used?

If you write / create a function that takes a type, for example, UIView.Type , and not an instance, for example, UIView() then you should write T.Type as the parameter type. What it expects as a parameter can be: String.self , CustomTableView.self , someOtherClass.self .

But why does a function need a type?

Usually a function that requires a type is a function that creates objects for you. I can recall two good examples:

  1. register function from table
 tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell") 

Please note that you passed CustomTableViewCell.self . If later you try to remove a CustomTableViewCell type from the tableView but do not register a CustomTableViewCell type, then it will fail because tableView did not remove from the queue / did not create any viewview elements of the CustomTableViewCell type cell.

  1. decoding function from JSONDecoder . Link example
 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) 

Please note try decoder.decode(GroceryProduct.self, from: json) . Since you passed GroceryProduct.self he knows that he needs to instantiate an object of type GroceryProduct . If he can’t, it gives an error

  1. For an alternative workaround where types are needed, see the following question: Swift cannot determine a universal type when a universal type is passed through a parameter . The accepted answer offers an interesting alternative.



More on the insides and how it works:

.Type of

The metatype of a class, structure, or enumeration type is the name of that type, followed by .Type. The metatype of the protocol type, not the specific type that matches the protocol at runtime, is the name of that protocol, followed by .Protocol. For example, the metatype of the SomeClass class SomeClass is SomeClass.Type and the SomeProtocol protocol SomeProtocol is SomeProtocol.Protocol .

From Apple: Meta Type

AnyClass is under the hood

 typealias AnyClass = AnyObject.Type // which is why you see T.Type 

Mostly AnyClass , where you see AnyClass , Any.Type , AnyObject.Type , because it needs a type. The very common place we see is when we want to register a class for our tableView using register func.

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

If you are not sure what Swift means. do then then see comments from here

The above can also be written as follows:

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

.self

You can use postfix self-expression to access the type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not an instance of the type that matches SomeProtocol at run time. You can use an expression of type (of :) with an instance of a type to access dynamic instance types as a value, as shown in the following example:

From Apple: Meta Type




Playground Code:

Simple example

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

Hard example

 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) The compile-time type of someInstance is BaseClass, and the runtime type of someInstance is SubClass */ type(of: someInstance) == SubClass.self // TRUE type(of: someInstance) == BaseClass.self // FALSE 

I highly recommend reading Apple's type documentation . See also here

+14
Jan 17 '17 at 23:44 on
source share

They appear in different places syntactically.

In the syntax place where you need to specify a type, Something.Type is a valid type corresponding to a type that is a metatype (which is a metaclass for classes) Something . Something.self not a valid syntax for a type.

In the syntax place where you need to write an expression, Something.self is a valid expression. This is an expression of type Something.Type , and value is a thing (a "class object" in the case of classes) that represents the type Something . Something.Type not a valid expression syntax.

+9
Jul 15 '15 at 21:29
source share



All Articles