1

How can i create array which will hold objects belonging a specific class.

class BaseObject {}

class Derived1: BaseObject {}
class Derived2: BaseObject {}
class Derived2: BaseObject {}

I need to create array in which will hold only Object derived from BaseObject

Something like - var array : [BaseObject.Type] = []

Is there a way to specify this ?

Also, I should be able to use it something like this

if let derived1 = object as? [Derived1] {

}
else if let derived2 = object as? [Derived2] {

}
4
  • 2
    var array = [BaseObject]() Commented Oct 16, 2017 at 3:11
  • I want to restrict array to use a specific class object. If i create an array with base class. Then i can add any derived class, i rather want to restrict it to use only 1 derived type based on instance created. Commented Oct 16, 2017 at 4:08
  • If you want to restrict it to use only 1 derived type – which contradicts the information in the question – use var array = [Derived1]() Commented Oct 16, 2017 at 4:38
  • So basically you need to have an array that is declared as a heterogenous array, but behaves like an homogenous one? Commented Oct 16, 2017 at 5:19

1 Answer 1

1

You can obviously define your array as an array of BaseObject:

var objects: [BaseObject] = []  // or `var objects = [BaseObject]()`

But it's going to let you create a heterogenous collection (of either BaseObject or Derived1 or Derived2 or of any other subclass). That's a core OO design concept (the Liskov substitution principle) that any subclass of BaseObject should (and will) be permitted.

If all you want is to say that you can only have an array of one of the subtypes, you can obviously just define your array as such, e.g.:

var objects: [Derived1] = []

That will obviously allow only Derived1 objects (and any subclasses of Derived1.


90% of the time, the above is sufficient. But in some cases, you might needs some collection with methods that require some inherited base behavior, but for which you don't want to allow heterogenous collections. In this case, I might consider a more protocol-oriented pattern:

  1. Bottom line, should we be subclassing, or should we be using a protocol-oriented approach? I.e. is BaseObject actually something you'll instantiate for its own purposes, or is it there merely to define some common behavior of the subclasses. If the latter, a protocol might be a better pattern, e.g.:

    protocol Fooable {
        func foo()
    }
    
    // if you want, provide some default implementation for `foo` in an
    // protocol extension
    
    extension Fooable {
        func foo() {
            // does something unique to objects that conform to this protocol
        }
    }
    
    struct Object1: Fooable {}
    struct Object2: Fooable {}
    struct Object3: Fooable {}
    

    This yields the sort of behavior that you may have been using in your more OO approach, but using protocols. Specifically, you write one foo method that all of the types that conform to this protocol, e.g., Object1, Object2, etc., can use without having to implement foo themselves (unless, of course, you want to because they need special behavior for some reason).

  2. Because this eliminates the subclassing, this then opens the door for the use of generics and protocols that dictate some generalized behavior while dictating the homogenous nature of the members. For example:

    struct FooCollection<T: Fooable> {
        private var array = [T]()
    
        mutating func append(_ object: T) {
            array.append(object)
        }
    
        // and let's assume you need some method for your collection that
        // performs some `Fooable` task for each instance
    
        func fooAll() {
            array.forEach { $0.foo() }
        }
    }
    

    This is a generic which is a homogenous collection of objects that conform to your protocol. For example, when you go to use it, you'd declare a particular type of Fooable type to use:

    var foo = FooCollection<Object1>()
    
    foo.append(Object1())  // permitted
    foo.append(Object2())  // not permitted
    
    foo.fooAll()
    

Now, I only went down this road because in comments elsewhere, you were inquiring about generics. I'd personally only go down this road if the (a) collection really needed to be homogenous; and (b) the collection also wanted to implement some shared logic common to the protocol. Otherwise, I'd probably just stick with a simple [Derived1] (or [Object1]). The above can be powerful when needed, but is overkill for simpler situations.

For more discussion about protocol oriented programming, the homogenous vs heterogenous behavior, traditional stumbling blocks when you're coming from a traditional OO mindset, I'd refer you to the WWDC 2015 video, Protocol-Oriented Programming in Swift, or it's 2016 companion video that builds upon the 2015 video.

Finally, if you have any additional questions, I'd suggest you edit your question providing details on a practical problem that you're trying to solve with this pattern. Discussions in the abstract are often not fruitful. But if you tell us what the actual problem you're trying to solve with the pattern in your question, it will be a far more constructive conversation.

Sign up to request clarification or add additional context in comments.

1 Comment

This is what i was looking for. Thanks @Rob

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.