Types and meta types in swift

Omar Abdelhafith
iOS App Development
5 min readNov 9, 2015

--

Knowing the types and meta-types in swift is not as important as in Objc. Where in objective c, you can instantiate an object out of a class name or modify classes at runtime, it’s not possible in pure swift.

The fact that swift is a language that supports generics, and has little to no reflection capabilities, knowing and dealing with types and meta-types is not a very common task.

However, there are times when you need to know what type your instances (or classes) are. In that area, swift provides two ways of getting the types; calling dynamicType on an instance, or self on a Class/Structure.

Type.self

The meta type of a type can be found by calling .self on a type. The returned type can either be a Class meta-type, a Struct meta-type or a Protocol meta-type.

Even if the above look similar, they act different. The type return from calling NSString.self looks similar to an Objective C class. However, it has other methods defined in swift extensions, for example, calling NSString.self.className() returns “NSString”

The object returned from calling MyClass.self is the swift metaType of MyClass. This object exposes init function and all the method defined in this class as curried method (read Instance Methods are Curried Functions in Swift).

If we pass MyClass.self to NSStringFromClass we get the mangled class name.

String.self returns a similar to calling self on a swift class. A difference to note here, if we pass it to NSStringFromClass we get a compilation error. This should not be surprising as string is a struct and not a class.

dynamicType

If .self is used on a Type to returns its metatype, dynamicType is used on an instance to return its type. The type returned is the same returned when calling .self on the instance static type.

Comparing the dynamic type to the static type for most of the struct and types; we can compare instances of MyClass as follows:

However, that won’t work for String, Int and Double.

I think that won’t work since String, Double and Int are special types in swift. The fact that swift can seamlessly change them to Foundation types make direct comparing them impossible.

Update: Joe Groff, a member of the swift team @apple, commented on the above issue. It seems to be a bug with swift type checking (tweet below)

This makes the comparision between the dynamicType and Type.self possible:

A radar for this issue can be found here rdar://23487272.

Comparing types directly is considered bad practice and is discouraged. The safe swift way to correctly check the type of an instance we must swift’s is statement. To compare the doubles from above we would use (please ignore swift warning us that the result is always true)

We can create a new instance from a type. For example to create an instance from MyClass we can use the following:

The above won’t work for the dynamicType:

As the error describes, the solution is to add a required init to MyClass:

Holding a metatype references

When storing the result of “”.dynamicType or String.self to a variable, the inferred type is String.Type. String.Type can so be used to annotate meta type variables:

Variable annotated with String.Type or any Struct.Type can only store that struct meta-type. The compiler won’t allow us to store another metatype to the same variable:

For classes, since they can be subclassed, the behaviour is different. A BaseClass.Type can also hold references of SubClass.Type.

Bellow we store NSDictionary.self and NSMutableDictionary.self to the same variable:

Note that the opposite won’t work, if we annotated the type with NSMutableDictionary.Type the compiler won’t allow us to store a reference of NSDictionary.self.

A Protocol.Type variable, unsurprisingly, can hold a reference to any type thats implementing that protocol:

To note here, only protocols that don’t have associated type or Self requirements can be used to annotate variables. Protocols that have Self or associated type requirements can only use as generic constraints.

As a final note, variables annotated with Any.Type can well, hold any type, weather the type is a structure or a class.

AnyObject.Type on the other hand, can hold any reference to a class meta type.

As always for notes and followup you can find me here @ifnotrue

--

--

Omar Abdelhafith
iOS App Development

Software developer @Facebook, previously @zendesk. In ❤ with λ, Swift, Elixir and Python. Check my Github https://github.com/nsomar.