Can I cast a metaclass object to a protocol type in Swift? - swift

Swift inherited Objective-C's metaclass concept: classes themselves are also considered objects. A class Foo's object's class is Foo.self, and it is of type Foo.Type. If Foo inherits from Bar, then Foo.self can be assigned to a variable of type Bar.Type, too. This has at least two benefits:
it allows to override "static methods";
it's easy to create an instance of an unknown class in a type-safe way and without using reflection.
I'm particularly looking at the second one right now. Just to be sure that everybody understands what I'm after, here's an example:
class BaseFoo {
var description: String { return "BaseFoo" }
}
class DerivedFoo: BaseFoo {
override var description: String { return "DerivedFoo" }
}
let fooTypes: [BaseFoo.Type] = [BaseFoo.self, DerivedFoo.self] // metaclass magic!
for type in fooTypes {
let object: BaseFoo = type() // metaclass magic!
println(object)
}
Now, I have an array of AnyClass objects (any metaclass instance can be assigned to AnyClass, just like any object can be assigned to AnyObject), and I want to find which ones implement a given protocol. The protocol would declare an initializer, and I would instantiate the class just like I do in the example above. For instance:
protocol Foo {
init(foo: String)
}
class Bar: Foo {
required init(foo: String) { println("Bar initialized with \(foo)") }
}
class Baz {
required init() { println("I'm not a Foo!") }
}
let types: [AnyClass] = [Bar.self, Baz.self]
So far so good. Now, the problem is determining if the class implements the protocol. Since metaclass instances are polymorphic, I'd expect to be able to cast them. However, I'm apparently missing something, because Swift won't let me write this:
for type in types {
if let fooType = type as? Foo.Type {
let obj = fooType(foo: "special snowflake string")
}
}
The compiler error I get is:
error: 'Foo' is not identical to 'AnyObject'
Is there any way to determine if a metaclass instance represents a class that implements a protocol, and is there any way to cast that instance into a protocol type?
I tried to declare Foo as a class protocol, but it's apparently not enough.
EDIT: I just tried with the Any type, and while it doesn't cause a syntax error, it crashes the Swift compiler.

As of Xcode 7 beta 2 and Swift 2 it has been fixed. You can now write:
for type in types {
if let fooType = type as? Foo.Type {
// in Swift 2 you have to explicitly call the initializer of metatypes
let obj = fooType.init(foo: "special snowflake string")
}
}
Or if you only want type as type Foo.Type you can use for case
for case let type as Foo.Type in types {
let obj = type.init(foo: "special snowflake string")
}

Related

Make initializer generic without type in function signature

I have broken down a more complex matter to this class. This way it doesn’t make sense, but it is easier to talk about:
class GenericClass<Type: Any> {
var object: Type?
enum DataType {
case string, integer
}
init(dataType: DataType) {
switch dataType {
case .string:
object = "string" // Cannot assign value of type 'String' to type 'Type'
case .integer:
object = 1 // Cannot assign value of type 'Int' to type 'Type'
default:
object = nil
}
}
}
How can I make this initializer infer the type Type when there is no reference in the function signature?
I asked a related question before (probably with to much cluttered detail): Make Generic Class Codable
Not sure if this answers your question but this is how you are supposed to create an initializer for a generic structure/class without a specific type in the function signature (generic initializer):
class GenericClass<T> {
let object: T
init(_ object: T) {
self.object = object
}
}
let stringClass = GenericClass("string")
print(stringClass.object)
let intClass = GenericClass(1)
print(intClass.object)
This will print
string1
The actual goal/benefit of generics is to get rid of type checks at runtime.
Referring and in addition to Leo's answer if you want to constrain the types to String and Int do it at compile time
protocol GenericClassCompatible {}
extension String : GenericClassCompatible {}
extension Int : GenericClassCompatible {}
class GenericClass<T : GenericClassCompatible> {
let object: T
init(_ object: T) {
self.object = object
}
}
If the type in the init method is not String or Int you'll get an error at compile time.

Cast T to generic superclass with unknown type

Let's say I have an array of type Foo with FooBar objects in it.
Bar <T> class is a generic class that inherits from Foo.
Then I have multiple FooBar classes, that inherits from Bar<T>, each with different generic type. (Bar<Int>, Bar<String>).
The problem is that I need to walk through the array of type Foo, check if na object is of type Bar<T>, cast it to Bar and set it's property.
Buty Swift won't allow me to cast to unknown type <T> and Bar<Any> doesn't match Bar<Int> or another...
I came up with two possible solutions - add new class to the hierarchy that inherits from Foo and is parent of Bar, but is not generic, and cast to this one or implement a protocol (which seems as much better solution).
What I'm really not sure about is if protocols are meant for this kind of stuff. In C-like lang, I would use an interface probably.
//Edit: Sample code
class Foo {
}
class Bar<T> : Foo {
var delegate : SomeDelegate
}
class FooBar: Bar<Int> {
}
class FooBar2: Bar<String> {
}
let arr : [Foo] = [ FooBar(), FooBar2(), Foo() ]
for item in arr {
// this is the problem - I need to match both String,Int or whathever the type is
if let b = item as? Bar<Any> {
b.delegate = self
}
}

What does self refer to when called on a type in Swift? [duplicate]

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
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()
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()

Swift metatype (Type, self)

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
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()
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()

Can we test if objects conforming to the same protocol are identical in swift without casting?

I was trying to test if two objects generated from a factory were identical, but the compiler does not seem to allow identity checking of objects that merely conform to the same protocol. Casting both objects to AnyObject seems fine however. Is there anyway to avoid what seems like unnecessary casting?
Here is a simple example the demonstrates what I am seeing (in swift 1.2)
protocol FooBar {
}
class Foo: FooBar {
}
class Bar {
let foo1: FooBar?
let foo2: FooBar?
init() {
foo1 = Foo()
foo2 = Foo()
if foo1! as? AnyObject === foo2! as? AnyObject { // this is fine
}
if foo1! === foo2! { // Birnary operator '===' cannot be applied to two FooBar operands
}
}
}
The identity operator === can only be applied to references, i.e. instances of classes.
If all types conforming to the FooBar protocol are classes then
you can declare it as a “class-constrained protocol”
protocol FooBar : AnyObject { }
(AnyObject is the protocol to which all classes implicitly conform.)
Then
if foo1! === foo2! { ... }
compiles and works as expected, because the compiler "knows" that
both operands are references to a class instance.