Dragonspell
Dragonspell

Reputation: 347

Inherit from class with private initializer?

Consider the following class hierarchy in Swift:

Class Hierarchy

GMSMarker is a class provided by the GoogleMaps library. It has two public initializers (one designated, one convenience).

MapItem, ClusterItem and Cluster are part of my model. I don't want to allow construction of MapItem objects; only ClusterItems and Clusters. Since Swift doesn't have abstract classes, having a private initializer would be sufficient for my purposes. However, given that MapItem inherits from GMSMarker with a convenience constructor, I can't simply override the designated initializer as private.

Given the rules of initializer inheritance in Swift, the only way that I've been able to prevent construction of the MapItem class is by declaring a new private initializer with a different signature so that the base class initializers aren't inherited.

class MapItem : GMSMarker {

    private init(dummyParam: Int) {
        super.init()
    }
}

So far so good. Now, when trying to create my initializer for the ClusterItem class, I run into a problem.

class ClusterItem : MapItem {

    weak var post: Post?

    init(post: Post) {
        self.post = post
        super.init(dummyParam: 0)
    }
}

I receive the following compiler error on the line that calls the super.init(): 'MapItem' does not have a member named 'init'.

If I omit the call to super.init, I receive the following error: Super.init isn't called before returning from initializer.

Is there any way of accomplishing what I want in swift. I would like to keep the inheritance hierarchy as is if possible because MapItem contains some common implementation code for ClusterItem and Cluster. Furthermore, I would like to be able to reference both ClusterItems and Clusters using a collection of MapItems.

Upvotes: 2

Views: 2341

Answers (1)

Sulthan
Sulthan

Reputation: 130162

There are various ways to solve this issue:

  1. Declare the initializer as internal, that will give you module access and your subclass will be able to call it.

  2. Declare the classes in the same file, then private won't be an issue anymore (private enables access from the same file).

  3. Instead of abstract classes, you can make MapItem a protocol and ClusterItem and Cluster could inherit from GMSMarker directly. However, this solution may not be good depending on your exact needs.

Upvotes: 1

Related Questions