Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Swift, how do I prevent a function from being called on a subclass?

I have a base class that stores a lot of other data objects within some data structures, and this class manages those data objects in my collections through a group of add/remove functions that keep my data structures in sync.

Now I go to subclass this base class, and the subclass is just like the base class except that it has special rules for what kinds of data objects it will accept (it looks at the values on the data objects, and rejects them if the values aren't right). Because of this "validity" check, I created a new function just for the subclass called change. In the change function, it examines all of the incoming data objects and verifies that they are ok, and replaces all of the data objects in the data structures with these data objects.

The problem is that I don't want someone to be able to make a subclass object and allow them to call the base class add/remove functions, because I only want the subclass to be able to be changed through the subclass's change function.

I haven't found a good way to "disable" the use of those base class functions in the subclass. I can override the functions and implement empty implementations, but there's no feedback to the caller that the function didn't do anything. And if I use something like fatalError, it isn't compile time, it's runtime.

My other thoughts are to break the functionality of the base class into multiple protocols, and change the base class to simply have all of the data structures, but conforming to none of the protocols and then have multiple subclasses, where one that wants the add functionality can inherit from the base and additionally conform to the add protocol, but one that doesn't want add or remove can inherit from the base, and simply not conform to any of the protocols and instead create their own change functions to modify the data structures.

Here's a simpler hierarchy to explain:

class Parent {
  
  func doThis() { print("Parent Did This") }
  func doThat() { print("Parent Did That") }
  
}

class Child: Parent {
  
  override func doThis() {
    print("Child Did This")
  }
  
  // I want this to be a compile time error
  override func doThat() {
    print("Not Supported")
    return
  }
  
}

Is there an easier way to "hide" a function in a subclass?

EDIT 1

To better explain my proposed solution, and whether or not there is an easier way to achieve it with my current hierarchy, here's what the hierarchy would have to look like using some protocols:

protocol CanDoThis {
  func doThis()
}

protocol CanDoThat {
  func doThat()
}

class Parent {
  // Important properties that all children should have
  var property1: Int = 0
  var property2: String = ""
}

class Child1: Parent, CanDoThis {
  func doThis() { print("Child1 Can Do This") }
}

class Child2: Parent, CanDoThat {
  func doThat() { print("Child2 Can Do That") }
}

class Child3: Parent, CanDoThis, CanDoThat {
  func doThis() { print("Child3 Can Do This") }
  func doThat() { print("Child3 Can Do That") }
}
like image 849
Tim Fuqua Avatar asked Jan 15 '16 00:01

Tim Fuqua


People also ask

Can we prevent a method from being overridden in Swift?

Preventing OverridesYou can prevent a method, property, or subscript from being overridden by marking it as final. Do this by writing the final modifier before the method, property, or subscript's introducer keyword (such as final var , final func , final class func , and final subscript ).

What is override function in Swift?

Swift version: 5.6. The override is used when you want to write your own method to replace an existing one in a parent class. It's used commonly when you're working with UIViewControllers , because view controllers already come with lots of methods like viewDidLoad() and viewWillAppear() .

How do you override property in Swift?

We use the override keyword to declare method overriding. For example, class Vehicle { func displayInfo(){ ... } } class Car: Vehicle { // override method override func displayInfo() { ... } }

What is difference between subclass and extension in Swift?

The new subclass will inherit all the capabilities of the parent class, but may then be extended to add the missing functionality. Swift extensions provide a useful alternative option to adding functionality to existing classes without the need to create a subclass.


1 Answers

Disclaimer

The protocol version would probably be better design - see the Leskov Substitution Principle amount the other things you mentioned.

Answering the question

You can use the attribute @available() (see Swift -> Language Reference -> Attributes).

class Parent {
    func doThis() { print("Parent Did This") }
    func doThat() { print("Parent Did That") }
}

class Child: Parent {
    override func doThis() {
        print("Child Did This")
    }

    @available(*, unavailable, message:"Child can't doThat")
    override func doThat() {
        print("Not Supported")
    }
}


let parent = Parent()
parent.doThis()
parent.doThat()

let child = Child()
child.doThis()
child.doThat()

You get the following error message on child.doThat():

'doThat()' is unavailable: Child can't doThat

However you can get around this by doing the following (again, see Liskov substitution principle):

let maybeChild: Parent = Child()
maybeChild.doThis()
maybeChild.doThat()
like image 134
Kevin Avatar answered Oct 13 '22 15:10

Kevin