Dan
Dan

Reputation: 675

The proper way to inherit a CustomViewController with "dependencies"

Recently I wrote an app with one single scene and ViewController. I had to set a custom background picture for the View, which the ViewController manages (i.e. my top view contained the UIImageView). Later on I had to implement some logic in ViewController, so that it properly rotates/changes the picture when the screen is rotated. Also I had to overwrite some properties like preferredStatusBarStyle for the ViewController.

Now I have to implement a couple more scenes / screens in my app and it turns out that they all must have the same design as this currently present screen, so I think it makes sense if I create a CommonViewController which contains this common rotation-related logic for background picture, so that I can inherit all my other ViewControllers from this CommonViewController. The only problem I have is that CommonViewController "requires" that the view it manages has a backgroundPicture: UIView property, which I don't know how to ensure.

If I create a new file CommonViewController together with XIB-file, I can add the backgroundPicture image view in XIB and connect it with code (via regular "control-drag" approach), but apparently this won't work, as there is no guarantee that the views which inherit CommonViewController will have this property. What is the correct way to solve this issue without hacks on iOS in Swift?

Unfortunately I could not find a solution, maybe I've been searching for something wrong. It seems that I somehow need to inherit a CommonViewController for each scene (for each CustomViewController), but also I have to somehow set the top view of each of these controller's to be equal to some CommonView, so that CommonViewController does not crash when I try to access @IBOutlet weak var backgroundPicutre: UIImageView!.


The obvious way would be to define some method or property in the CommonViewController, so that the controllers which inherit it, can implement / override it, but it seems a bit hacky as it still requires copy-pasting in each ViewController which inherits CommonViewController.

How I imagined the solution: I create CustomViewController: CommonViewController, then I create a view controller in my Storyboard and change the "Class" property to "CustomViewController" (in property editor), then I select the view which corresponds to this newly added controller and change the "Class" property to "BackgroundImageView. But I'm not sure if it's the correct way to do (also I doubt thatCustomViewControllerwill properly "connect" itsIBOutletfieldbakcgroundImageViewwith the correspondingUIViewfromBackgroundImageView`, that's why I wanted to ask experts what they think about it.

Upvotes: 0

Views: 86

Answers (1)

NShiny
NShiny

Reputation: 1156

I think you should define your base controller (CommonViewController) entirely in code, i.e. don't use no xibs / storyboards for the base controller. It doesn't mean you should rid off storyboards / xibs completely. Interface for alll other view controllers except CommonViewController may still be implemented with xibs / storyboards.

In this case CommonViewController implementation may look like this:

import UIKit

class CommonViewController: UIViewController {
    // use this property every time you need to 
    // manipulate backgroundPicture
    var backgroundPicture: UIImageView  = {
        // Replace with your image name
        let image = UIImage(named: "BackgroundPicture")!
        let imageView = UIImageView()
        imageView.image = image
        return imageView
    }()

    override func viewDidLoad() {
        // If subclass overrides viewDidLoad() 
        // it should contain super.viewDidLoad()
        super.viewDidLoad()

        view.addSubview(backgroundPicture)

        // Align backgroundPicture to bounds of superview
        // You can remove this code and implement
        // your own alignment with frames or Autolayout
        backgroundPicture.frame = view.bounds

        // Send backgroundPicture to back of the view
        // Otherwise backgroundPicture may overlap views added in subclasses
        view.sendSubviewToBack(backgroundPicture)
    }
    
    override func viewDidLayoutSubviews() {
        // If subclass overrides viewDidLayoutSubviews()
        // It should contain super.viewDidLayoutSubviews() 
        super.viewDidLayoutSubvews()

        // Align backgroundPicture to bounds of superview
        // You can remove this code and implement
        // your own alignment with frames or Autolayout
        backgroundPicture.frame = view.bounds
    }
}

Upvotes: 1

Related Questions