Image for post
Image for post

Types and meta types in swift

Omar Abdelhafith
Nov 9, 2015 · 5 min read

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.

Image for post
Image for post

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.

Image for post
Image for post

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:

Image for post
Image for post

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:

Image for post
Image for post

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)

Image for post
Image for post

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

Image for post
Image for post

The above won’t work for the dynamicType:

Image for post
Image for post

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

Image for post
Image for post

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:

Image for post
Image for post

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:

Image for post
Image for post

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:

Image for post
Image for post

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:

Image for post
Image for post

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.

Image for post
Image for post

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

Image for post
Image for post

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

Image for post
Image for post

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

iOS App Development

Stories and technical tips about building apps for iOS…

Omar Abdelhafith

Written by

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

iOS App Development

Stories and technical tips about building apps for iOS, Apple Watch, and iPad/iPhone

Omar Abdelhafith

Written by

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

iOS App Development

Stories and technical tips about building apps for iOS, Apple Watch, and iPad/iPhone

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store