Why must constructing an object of class type 'someClass' with a metatype value use a 'required' initializer?
Consider the case where we also have a subclass:
class SomeClass {
}
class SomeSubclass : SomeClass {
}
If you store the class type in a variable:
var anotherClass = SomeClass.self
The variable anotherClass
is of type SomeClass.Type
.
You can later assign this variable to a subclass:
anotherClass = SomeSubclass.self
This is valid because SomeSubclass.Type
is a SomeClass.Type
. At this point, anotherClass()
would fail if the initializer is not implemented in the subclass. This is what the compiler is protecting against.
In your sample code, this is impossible: you used let
instead of var
so changing the type is impossible. It may be that the safety checks just aren't nuanced enough to notice this.
Using metatype in closure
I think I found a solution, I removed the return type to make it implicit and it worked. Probably it is some kind of swift compiler bug. End result:
let type = String.self
let closure = { () in
return type.init()
}
Using type as a value, why is the self keyword required here?
Self-answering, with help of comments, I was able to find out the reason:
Using .self
after the type name is called Postfix Self Expression:
A postfix self expression consists of an expression or the name of a
type, immediately followed by.self
. It has the following forms:expression.self
type.self
The first form evaluates to the value of the expression. For example,
x.self
evaluates tox
.The second form evaluates to the value of the type. Use this form to access a type as a value. For example, because SomeClass.self evaluates to the SomeClass type itself, you can pass it to a function or method that accepts a type-level argument.
Thus, the .self
keyword is required to consider the type as a value capable of being passed as an argument to functions.
How to model a more limited version of class with shared code?
You can use a protocol with an associated type:
protocol Shelter {
associatedtype AnimalType
func take(x: AnimalType)
}
extension Shelter {
func usefulMethod(...)
}
class AnimalShelter : Shelter {
typealias AnimalType = Animal
func take(x: Animal) { ... }
}
class DogShelter : Shelter {
typealias AnimalType = Dog
var dogMedianCuteness: String = "normal (= very cute)"
func take(x: Dog) {}
}
Swift - what's the difference between metatype .Type and .self?
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
Let's say that each entity is represented by two things:
Type:
# entitiy name #
Metatype:
# entity name # .Type
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
Source.
You can quickly notice that this is recursive and there can by types like (((T.Type).Type).Type)
and so on.
.Type
returns an instance of a metatype.
There are two ways we can get an instance of a metatype:
Call
.self
on a concrete type likeInt.self
which will create a
static metatype instanceInt.Type
.Get the dynamic metatype instance from any instance through
type(of: someInstance)
.
Dangerous area:
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 yet another metatype which only exisits in context of protocols. That said, there is no way how we can express that we want only P.Type
. This prevents all generic algorithms to work with protocol metatypes and can lead to runtime crashes.
For more curious people:
The type(of:)
function is actually handled by the compiler because of the inconsistency .Protocol
creates.
// 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 { ... }
Related Topics
Uisplitviewcontroller in Portrait on iPhone Always Show Master and Detail in iOS 8
Update Core Data Object Order - Not Working
Get an Error When Trying to Get All the Photos from Phassetcollection.Fetchassetcollections
How to Add Initializers in Extensions to Existing Uikit Classes Such as Uicolor
.Dynamictype Is Deprecated. Use 'Type(Of ...)' Instead
Need Self to Set All Constants of a Swift Class in Init
Iterate an Array W/ Explicit Object Type in Swift
Do Local Notifications Need User Permission on iOS
Xcode10 - Dyld: Library Not Loaded for Pod Installed in Framework
iOS 11 Black Bar Appears on Navigation Bar When Pushing View Controller
iOS 10 App Crashes When Trying to Save Image to Photo Library
Module File's Deployment Target Is iOS9.0 V9.0 with Xcode 7/Swift 2
Get Resource Url from Project Specific Path