4

Suppose I have three classes:

import Foundation

class A {

    init() {
      print("A")
    }

}

class B {

    init() {
        print("B")
    }

}

class C {

    init() {
       print("C")
    }
}

I want to dinamically pass a string ("A", "B" or "C") as a function argument and then, inside the body of this function, create an instance of the class I passed. Is this possible? How?

I tried this one (and other variants) but with no luck:

func test(c:AnyObject){
    let _class = c()
    //...
}

test(c:A)

[UPDATE] Maybe the question is no different from the one @Code Different suggests but that question is old and there were so many changes in the language that one should try any suggested solution before finding the one that works as of today

1 Answers1

1

What could work is having a base class, let's call it BaseClass. Classes that needs to be used would inherit from BaseClass.

Then, in your function, you would pass it the desired type.

Here is a code snippet that demonstrates this technique:

class BaseClass { }

class A: BaseClass { ... }
class B: BaseClass { ... }
class C: BaseClass { ... }

func test(type: BaseClass.Type) {
    let someObject = type.init()
    // You can cast the object if required
}

test(type: A.self) // creates an object of class A
test(type: B.self) // creates an object of class B

Edit: If you really need a string to cast your types, you might consider doing some job prior to calling test. Getting the type in a switch case and then passing it to test should do.

Edit: It would also work with a protocol, as long as it defines the initializers you need, along with every functions that must be exposed:

protocol SomeProtocol: class {
    init()
    func someFunction()
}

class A {
    required init() {
        print("A")
    }
}

extension A: SomeProtocol {
    func someFunction() {
        print("Some function of A")
    }
}

class B {
    required init() {
        print("B")
    }
}

extension B: SomeProtocol {
    func someFunction() {
        print("Some function of B")
    }
}

class C {
    required init() {
        print("C")
    }
}

extension C: SomeProtocol {
    func someFunction() {
        print("Some function of C")
    }
}

func test(someType: SomeProtocol.Type) {
    let someObject: SomeProtocol = someType.init()
    someObject.someFunction()
}

test(someType: A.self) // creates an object of class A
test(someType: B.self) // creates an object of class B
Francis.Beauchamp
  • 1,323
  • 15
  • 28
  • The protocol is not working, while BaseClass works as long as you add a required init. I can't edit your code, but I suppose this let someObject type.init() should be let someObject = type.init() –  Jul 28 '17 at 05:50
  • 1
    @3000 added a version that works with protocol, tested in playground. Protocol needs to define the initializers used by the classes. – Francis.Beauchamp Jul 28 '17 at 12:23
  • It works fine, but I found that, if you add a method to every class, you must add it to the protocol too –  Jul 29 '17 at 07:04
  • @3000 true, it would be good to define your protocol by adding every apis required externally. Otherwise, you'd have to cast the object to know the specific functions he has (those that are not in the protocol). I added some changes that shows a way to do it. – Francis.Beauchamp Jul 29 '17 at 14:18