user1002430
user1002430

Reputation:

How to create an array of classes and instance objects with it in Swift?

I tried to ask this question previously but didn't clearly express my question, so I'll try again here. I also noticed a very similar sounding question, but it is asking for something entirely different.

I have the following code:

class Base {
    func launch(code1: Int, code2: Int) { ... }
}

class A: Base {}
class B: Base {}
class C: Base {}

let classes = [A.self, B.self, A.self, B.self, C.self]
for cls in classes {
    let obj = ???
}

I would like to instantiate an object of type cls inside the loop and do something with it. I might have duplicates inside the array, as shown. What do I put in place of the ??? to be able to instantiate the proper objects?

Upvotes: 7

Views: 4312

Answers (3)

R Menke
R Menke

Reputation: 8391

All you need is a required init, some way to create an instance that will be shared between all Types you want this to work for. A protocol that holds an init method will do fine.

Obviously this works simplest when the init does not require parameters.

Downside is that you do need to downcast the resulting instances.

protocol ZeroParamaterInit {
    init()
}

class Base : ZeroParamaterInit {
    func launch(code1: Int, code2: Int) {  }
    required init() {

    }
}

class A: Base {}
class B: Base {}
class C: Base {}

let classes : [ZeroParamaterInit.Type] = [A.self,B.self]
var instances : [Any] = []

for cls in classes {

    let instance = cls.init()
    instances.append(instance)

}

for instance in instances {

    if let test = instance as? A {
        print("A")
    }
    if let test = instance as? B {
        print("B")
    }
    if let test = instance as? C {
        print("C")
    }
}

Upvotes: 6

user3441734
user3441734

Reputation: 17534

import Foundation

class Base {}

class A: Base { var i: Int = 1 }
class B: Base { var i: String = "bravo" }
class C: Base { var i: Bool = true }

let classes = [A.self, B.self, A.self, B.self, C.self]

for cls in classes {
    var obj: Base? {
        switch cls {
        case is A.Type:
            return A()
        case is B.Type:
            return B()
        case is C.Type:
            return C()
        default:
            return nil
        }
    }
    dump(obj)
}


/*
▿ A
    ▿ Some: A #0
    - super: Base
    - i: 1
▿ B
    ▿ Some: B #0
    - super: Base
    - i: bravo
▿ A
    ▿ Some: A #0
    - super: Base
    - i: 1
▿ B
    ▿ Some: B #0
    - super: Base
    - i: bravo
▿ C
    ▿ Some: C #0
    - super: Base
    - i: true
*/

this is very close to R Menke solution ...

Upvotes: 0

Peyman
Peyman

Reputation: 3077

Alright, you'll love this link: http://ijoshsmith.com/2014/06/05/instantiating-classes-by-name-in-swift/

It walks you through the Swift library Obj ectFactory:

https://github.com/ijoshsmith/swift-factory

You really can't do this in Swift. You can, however, do it in Objective-C so you can simply write a wrapper that exposes a Swift interface where behind the scenes, actual object creation is done in Objective-C. That library is exactly what you're looking for.

You'd need to create a ObjectFactory like this:

let factory = ObjectFactory<MyClass>

Then you can instantiate an instance of MyClass like:

let myClass1 = factory.createInstance(className: "MyClassName")

Upvotes: 0

Related Questions