Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift metatype (Type, self)

Tags:

swift

I am trying to understand : "self, dynamicType, Type". I have this code :

class SomeClass {}

let cls : SomeClass.Type = SomeClass.self
let cls2 : SomeClass = SomeClass()

Are cls and cls2 the same thing ?

Can someone give some detail about the differences ? Thanks

like image 423
samir Avatar asked Jan 27 '16 10:01

samir


Video Answer


2 Answers

No, cls and cls2 are different things. The easiest way to understand the difference will be to extend your example like this:

class SomeClass {
    class func doIt() {
        print("I'm a class method. I belong to my type.")
    }

    func doItOnlyIfInstanceOfThisType() {
        print("I'm a instance method. I belong to my type instance.")
    }
}

And now let's take your cls:

let cls : SomeClass.Type = SomeClass.self
cls.doIt()

That will print I'm a class method. I belong to my type.. But you cannot invoke this:

cls.doItOnlyIfInstanceOfThisType() // causes a compilation error, PRO TIP: actually you can use this method as a func property, but I'll add the explanation for this later

Let's take your cls2. The only visible method of it is doItOnlyIfInstanceOfThisType because it's an instance method (of this type).

let cls2 : SomeClass = SomeClass()
cls2.doItOnlyIfInstanceOfThisType()

So the difference between them is that cls is a type and cls2 is an instance of this type.

A little bit more knowledge about why SomeClass.self and SomeClass()?

The type of a class also exists in memory (it has for example its own methods), as a singleton representing the Type (not an instance of this type - that's something different). If you call self on a Type like this SomeClass.self you will get a singleton instance representing the SomeClass Type.

SomeClass() invokes the init() method of SomeClass, a constructor that creates an instance of SomeClass.

PRO Tip

You can manipulate a Type instance function (like closures/blocks in ObjC). It's a generated class method. But you must pass an instance of the type that you take this method from as an argument, like this:

let myFunc :()->() = cls.doItOnlyIfInstanceOfThisType(cls2)
myFunc()
like image 138
Radosław Cięciwa Avatar answered Oct 02 '22 04:10

Radosław Cięciwa


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

You can use the postfix self expression to access a 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 a type that conforms to SomeProtocol at runtime. You can use a dynamicType expression with an instance of a type to access that instance’s dynamic, runtime type as a value, as the following example shows:

class SomeBaseClass {
    class func printClassName() {
        print("SomeBaseClass")
    }
}
class SomeSubClass: SomeBaseClass {
    override class func printClassName() {
        print("SomeSubClass")
    }
}
let someInstance: SomeBaseClass = SomeSubClass()
someInstance.dynamicType.printClassName()
// prints "SomeSubClass"

The compile-time type of someInstance is SomeBaseClass, the runtime type of someInstance is SomeSubClass

You can use the identity operators (=== and !==) to test whether an instance’s runtime type is the same as its compile-time type.

if someInstance.dynamicType === SomeBaseClass.self {
    print("The dynamic type of someInstance is SomeBaseCass")
} else {
    print("The dynamic type of someInstance isn't SomeBaseClass")
}

More detail -> The Swift Programming Language: Types

Swift 3.0:

.dynamicType is deprecated, you should use type(of:) to get its meta type:

type(of: someInstance).printClassName()
like image 38
a_tuo Avatar answered Oct 02 '22 03:10

a_tuo