5

I have an array of objects of various types and an array of types. For each object, I'd like to iterate over the array of types and see if the object is that type. Something like this:

class Parent {}
class ChildA: Parent {}
class ChildB: Parent {}
class GrandChildA: ChildA {}

var objects: [Any] = ["foo", ChildA(), ChildA(), ChildB(), GrandChildA()]
var classes = [Parent, ChildA, ChildB] // This line doesn't compile!!

for obj in objects {
    for cls in classes {
        if obj is cls {
            NSLog("obj matches type!")
        }
    }
}

This doesn't work because you can't store classes in an array. As I understand, you can store class types such as ChildA.self:

ChildA().dynamicType == ChildA.self // true

But this doesn't handle subclasses:

ChildA().dynamicType == Parent.self // false

Obviously the is operator solves the subclass case:

ChildA() is Parent // true

But if I want to use is, I don't know how to store the class types in an array.

Can I accomplish what I want somehow using Swift and some reflection voodoo?

Sorry if the title is misleading -- I don't understand this well enough to form a proper question.

Brent Traut
  • 5,614
  • 6
  • 29
  • 54

1 Answers1

-2

By adding a title to each class you can switch on them. Also, have you thought of using a protocol instead of a superclass?

Maybe something like this:

protocol Parentable {
    var title : String { get set }
}

class ChildA : Parentable{
    var title: String
    init() {
        self.title = "ChildA"
    }
    init(title: String){
       self.title = title
    }
}
class ChildB: Parentable {
    var title: String
    init(){
        self.title = "ChildB"
    }
}
class GrandChildA: ChildA {
    override init() {
        super.init(title: "GrandChild")
    }
}

var objects: [Parentable] = [ChildA(), ChildA(), ChildB(), GrandChildA()]

for obj in objects {
    switch obj.title {
    case "ChildA":
        print("Object is of type \(obj.title)")
    case "ChildB":
        print("Object is of type \(obj.title)")
    case "GrandChild":
        print("Object is of type \(obj.title)")
    default :
        print("Object is of type \(obj.title)")
    }
}

You could also do it with a superclass like this if you need the objects passed by reference:

class Parent {
    var title: String

    init() {
        self.title = "Parent"
    }
    init(title: String) {
        self.title = title
    }
}
class ChildA: Parent {
    override init() {
        super.init(title: "ChildA")
    }
    override init(title: String) {
        super.init(title: title)
    }
}
class ChildB: Parent {
    override init() {
        super.init(title: "ChildB")
    }
}
class GrandChildA: ChildA {
    override init() {
        super.init(title: "GrandChild")
    }
}

    var objects: [Parent] = [ChildA(), ChildA(), ChildB(), GrandChildA()]

    for obj in objects {
        switch obj.title {
        case "ChildA":
            print("Object is of type \(obj.title)")
        case "ChildB":
            print("Object is of type \(obj.title)")
        case "GrandChild":
            print("Object is of type \(obj.title)")
        default :
            print("Object is of type \(obj.title)")
    }
}
Dustin Spengler
  • 5,478
  • 4
  • 28
  • 36
  • 1
    I really appreciate the response but unfortunately this doesn't accomplish what I want. First, using strings requires a lot of extra overhead for me to maintain and is error prone. The language already handles all of this via ```dynamicType``` (see my example above). Second, your example doesn't handle the case of sub/superclasses: ```ChildB.title``` gives me no evidence that it is both a ```ChildB``` *and* a ```Parent```. – Brent Traut Aug 24 '16 at 19:31