Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a base view controller

I would like to have a BaseViewController that subclasses UIViewController, overrides one of it's methods, but also require it's subclasses to implement new ones.

My case is a bit more complex, but this simple case represents my problem:

My BaseViewController would override viewWillAppear to set it's title, but the title string would come from it's subclasses. I thought about some options, not sure if/which one of them is best.

1 - Class with error throwing methods (my current solution):

class BaseViewController: UIViewController {
  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    title = getTitle()
  }

  func getTitle() -> String {
    fatalError("Unimplemented method")
  }
}

2 - Receive the title in constructor:

class BaseViewController: UIViewController {
  var myTitle: String!

  convenience init(title titleSent: String) {
    self.init(nibName: nil, bundle: nil)
    myTitle = sentTitle
  }

  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    title = myTitle
  }
}

Note that this options gets really bad if there's more parameters to send

I thought that using protocol would be perfect, until I find out that (of course) protocols can't subclass a class.

Didn't anybody do anything like this before? I don't think so, please share your thoughts.

Update

I tried another way, but got stuck in a compiler error, would this ever work?

procotol BaseViewController {
  var myTitle: String { get }
}

extension BaseViewController where Self: UIViewController {
  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    title = myTitle
  }
}

The compiler says Method does not override any method from its superclass.

like image 922
gfpacheco Avatar asked Nov 19 '15 16:11

gfpacheco


People also ask

How do I create a new view controller?

To create a new view controller, select File->New->File and select a Cocoa Touch Class. Choose whether to create it with Swift or Objective-C and inherit from UIViewController . Don't create it with a xib (a separate Interface Builder file), as you will most likely add it to an existing storyboard.

How do I get a view controller?

If you need to find the view controller that is responsible for a particular view, the easiest thing to do is walk the responder chain. This chain is built into all iOS apps, and lets you walk from one view up to its parent view, its grandparent view, and so on, until it reaches a view controller.

How do I embed a view controller in navigation controller storyboard?

storyboard and embed our existing table view controller in a navigation controller: Select the existing table view controller. With the table view controller selected, in the Xcode menu, select Editor > Embed In > Navigation Controller .


1 Answers

I usually create protocol in which I declare what would be nice to have in the controllers. Then I check in the base controller if it's actually implemented and if so, just use the values, like this:

protocol ControllerType {
    var navigationTitle: String { get }
}

extension ControllerType {
    var navigationTitle: String {
        return "Default title"
    }
}

class BaseViewController: UIViewController {

    override func viewDidLoad() {
        if let controller = self as? ControllerType {
            self.title = controller.navigationTitle
        }
    }
}

class ViewController: BaseViewController, ControllerType {

    var navigationTitle: String {
        return "ViewController"
    }

    override func viewDidLoad() {
        super.viewDidLoad()    
    }
}

Downfall is you have to implement the ControllerType protocol and there's no way to enforce it.

like image 84
libec Avatar answered Oct 03 '22 07:10

libec