1

Wait, I know this question title looks very duplicated, but it really is not.
I have been searching for whole day but cannot find any good solution.

Definition of terms

BaseViewController: A class that extends UIViewController, responsible for some common behaviors across different subclassed ViewControllers.
VC: Short form of ViewController, I will use it from now on
dialog: In other words, popup; a VC that does not cover the whole screen, and is present modally.

Scenario

Let me use an example to illustrate my needs.

Let say I have an app that displays dialogs in different places.
These dialogs have something in common, including:

  1. They will blur the background when displayed
  2. They have a same width
  3. They have a same dialog container style (e.g. rounded corner radius)

And they also have non common things - the content inside the dialog container.

In order to reduce code duplication, I want to create a BaseDialogVC to implement the above 3 common things first, and then child class that subclass BaseDialogVC will provide the view inside the container.

Therefore, I created a storyboard file which contains BaseDialogVC and implemented the 3 common things using Interface Builder of storyboard.
It has an empty UIView that acts as a container for its child class to provide their content.
And then, I created a subclass of BaseDialogVC, for example, AddItemDialogVC. This AddItemDialogVC is then responsible for providing its content view, and the logic of this dialog.

Then I am stuck - I tried to instantiate from storyboard an AddItemDialogVC, but it will crash because storyboard does not have AddItemDialogVC. It only has BaseDialogVC.

Question

Actually, I know one alternative that can achieve similar things.
That is - I do not subclass BaseDialogVC, instead I instantiate it, and add subview to it by calling an instance method of it, passing in an UIView.

But I still very much want to know what's wrong with my original approach, or,
What is the best approach to this problem?

By "the best approach", I mean it effectively reduced duplication and is easy to maintain.

What I have tried

I found this post for changing BaseDialogVC to AddItemDialogVC. But even if it successfully created an AddItemDialogVC, the AppItemDialogVC cannot init its content view (A custom View that is subclass of UIView, and I got an "Thread 1: EXC_BAD_ACCESS" exception.

I think the most similar question out there is this thread.
However, the accepted answer does not elaborate enough; while the second most voted answer is the same as set_object that I have tried before.

FYI, my class for AddItemDialogView (NOT VC!):

class AddChoiceDialogView: UIView {

    @IBOutlet weak var rootView: AddChoiceDialogView!

    override init (frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init? (coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    private func commonInit () {
        Bundle.main.loadNibNamed("AddChoiceDialogView", owner: self, options: nil)
        addSubview(rootView)
        rootView.frame = self.bounds
        rootView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
    }

}
Sira Lam
  • 4,412
  • 24
  • 53
  • 1
    Similar to your alternative idea, it seems to me that your `BaseDialogVC` provides structure but needs a delegate or data source to customize its content. – Phillip Mills Feb 02 '18 at 14:01
  • A delegate! I obviously didn't think of that. But I cannot figure out the whole picture yet - I suppose the one that provides the delegate is a subclass of `BaseDialogVC`, if I am still using storyboard to create the structure of the dialog, how am I going to instantiate that subclass correctly? – Sira Lam Feb 02 '18 at 14:06
  • I don't think there's any need for the delegate to be a subclass. I'd think of `BaseDialogVC` as a `DialogPresenterVC` or something like that instead. It can ask the delegate for data to display or even a view to display if that's a better fit. – Phillip Mills Feb 02 '18 at 14:29
  • Now I understand your point. But think of it, I think I really need a subclass. Because I do not only need to provide the content (View), I also need to handles the corresponding logic of the dialog. – Sira Lam Feb 02 '18 at 14:33
  • OK, if you need view-specific logic, make your base dialog a container controller and provide it with a view controller to embed. (By the way, what's wrong with having the child controllers available in the storyboard if you want subclassing?) – Phillip Mills Feb 02 '18 at 15:10
  • @PhillipMills VC Container, that is another option to explore as well. I came up with one possible solution that I will give it a try: `BaseDialogVC` subclass `UIViewController`, but not referencing any storyboard. And init a subview from xib to `self.view`. From there on, `AddItemDialogVC` subclass `BaseDialogVC` and populates the content view. Does it sound make sense to you? As for what's wrong with having the child controllers in storyboard - I just want to reduce duplication of common characteristics they have. If that is a large project, that would be a mess if I want to change the bg – Sira Lam Feb 02 '18 at 15:15

0 Answers0