Can I apply a metaclass object to a protocol type in Swift?

Swift inherited the concept of the Objective-C metaclass: the classes themselves are also considered objects. The class class Foo is Foo.self , and it is of type Foo.Type . If Foo inherits from Bar , then Foo.self can also be assigned to a variable of type Bar.Type . This has at least two advantages:

  • it allows you to override "static methods";
  • it is easy to instantiate an unknown class with a safe type and without using reflection.

I'm looking at the second now. To be sure everyone understands what I need, here is 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 instance of a metaclass can be assigned to AnyClass , just like any object can be assigned to AnyObject ), and I want to find which ones implement this protocol, the Protocol will declare an initializer, and I would instantiate the class. as in the example above. For example:

 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. The problem now is whether the class implements the protocol. Since metaclass instances are polymorphic, I expect that I can distinguish them. However, I obviously missed something because Swift would not let me write this:

 for type in types { if let fooType = type as? Foo.Type { let obj = fooType(foo: "special snowflake string") } } 

Compiler Error:

error : "Foo" is not identical to "AnyObject"

Is there a way to determine if a metaclass instance represents a class that implements the protocol, and is there a way to pass this instance to the protocol type?

I tried to declare Foo as a class protocol, but apparently this is not enough.


EDIT : I just tried with type Any , and although it does not cause a syntax error, it throws a Swift compiler.

+7
metaclass swift
source share
1 answer

As of Xcode 7 beta 2 and Swift 2, it has been fixed. Now you can 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 want only 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") } 
+4
source share

All Articles