简体   繁体   中英

A class inherits another class and conforms to a protocol - trying to reconcile two interfaces

Hi guys. I have found myself fighting the type system, which probably means I am doing (or thinking) something totally wrong, and I need your programming eagle's eye to spot it.

In my app I have a settings view (controller) which displays views of different settings panes (which are ViewControllers) - one at a time, adding their view as its subview.

Now, here's my issue. Each settings pane is a class defined as follows:

protocol SettingsPane {
    var componentTitle: String { get }
    func saveState()
}

class SettingsPaneVC: UIViewController, SettingsPane {
...
}

Sometimes I need its UIViewController and other times the SettingsComponent part of the interface, and so I have found myself in a situation where I need to settle for one of these, and then force-downcast whenever I need the other one. E. g.:

var components: [SettingsPane] = [
    SomeSettingsPane(),
    AnotherSettingsPane(), 
    etc...
]

for component in components {

    (component as! UIViewController).view.frame = ....
}

// but...
...text = self.components.first!.componentTitle

What I am looking for is a solution which would allow me to get rid of downcasting. I have been trying to leverage the fact that anything conforming to SettingsComponent should always be a subclass of UIViewController , but I haven't come up with anything acceptable. So far, my attempts have resulted in such code:

protocol SettingsPane {

    var componentTitle: String { get }
    var view: UIView! { get set } //what I need from UIViewController
    func saveState()
}

Is there a way of making the entire UIViewController 's interface available through SettingsPane ? Or am I destined to list in SettingsPane specifically what I need?

If every SettingsPane is going to be a subclass of UIViewController , you could just create a SettingsViewController subclass.

class SettingsViewController : UIViewController {
    var componentTitle: String {
        fatalError()
    }

    func saveState() {
        fatalError()
    }
}

I realize there are some problems with this:

  1. You can't subclass anything else such as UITableViewController or UICollectionViewContorller .
    • This may be a deal-breaking, it may not be.
  2. You don't get compile errors when you don't implement the required methods, you get runtime errors if the methods are not overridden.
  3. Most of what you could do could be done with a protocol extension
    • extension SettingsPane where Self : UIViewController {}

Is there a way of making the entire UIViewController's interface available through SettingsPane?

This is a subclass.

Or am I destined to list in SettingsPane specifically what I need?

Yes, which might actually be a good thing. You might want to hide all of the UIViewController stuff away if you just need the UIView . You didn't specify what else you needed so that might be a terrible idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM