1

I have a lot of common logic, therefore all my viewControllers inherit from BaseViewController, BaseDetailsViewController or BaseWebViewController. The last two inherit from BaseViewController which inherits from UIViewController. The problem is I cannot use tableViews with static cells because my BaseDetailsViewController is not inheriting from UITableViewController.

I'v never used and inherited UITableViewController because the same could be achieved by inheriting from UIViewController, wiring it with an added UITableView and having implemented datasource and delegate methods. Therefore for the form type screens (SignUp or other data input screens), I use my own BaseDetailsViewController which adds nice and handy methods (input validation, custom styling, scrolling keyboard, handles input field navigation and etc.)

Using UITableViewController has two real benefits: 1) keyboard scrolling (if you use text fields) and 2) easy creation of your form UI elements inside on screen. The first benefit is irrelevant for me, because I'v already have my own implementation of this stuff inside BaseDetailsViewController. Regarding the second benefit, I'm creating my form inside scrollView which gives a lot of flexibility but it's a little bit more effort (especially when need to update the screen). Therefore I heard some guys implemented their own UITableViewController and then made it to inherit from their BaseViewController. Therefore I started to dig into this approach.

So far I'v came upon these two approaches:

  1. Recreate your own tableVC. Not clear how to make it work for static cells. Currently my demo app crashes if my ReplaceTableViewController is not implementing numberOfRows and cellForRow, and not shows static cells if I implement them with dummy content.
  2. method-swizzling. Not clear how to change class inheritance by injecting baseViewController inheritance for UITableViewController, thought still not clear which methods are needed to be added.

Anybody tried and want to share?

UPDATE I'm not using storyboards as I promote clean MVC - every screen as component should have its own Model, View (Xib), and controller, all stored in separate files to eliminate merge conflicts of multiple devs in large app projects (30+ screens). And therefore container view with embedded segue to tableViewController is also not an option.

UPDATE2 In case anybody would like to take a look why and how I'm doing this, here's a link to my open source template based new project generator framework which I started to publish recently.

Centurion
  • 14,106
  • 31
  • 105
  • 197
  • 1
    So why aren't you using a tvc? Your question is quite long and its not very clear what you're asking. – Schemetrical May 24 '15 at 07:51
  • So really you want to use your custom VC and also design your table in a storyboard with minimal code behind it? – Wain May 24 '15 at 08:10
  • @Schemetrical. All of my viewControllers directly or indirectly inherit from BaseViewController which inherits from UIViewController. This does not allow use tableView with static cells. I don't want to use tvc because then I won't be able to have common functionality (BaseViewController) on all of the viewControllers (no code duplication). The question is how to make static cells work without using tvc and storyboards. – Centurion May 24 '15 at 08:13
  • You should be using a separate class for common functionality (MVC), its good practice and much better than inheriting methods from a parent. You shouldn't inherit from one class if its only the common functionality you're looking for, unless the common functionality includes UI handling and customisation. – Schemetrical May 24 '15 at 08:39
  • @Schemetrical Very granular composition has its own disadvantages, like over complicates the code. Therefore sometimes there is a place for inheritance in this world too. If you don't agree then you should write your own theory about OOP which won't include inheritance at all. Anyway, the question was more about how to do it, not why because all the arguments where given, and there are always opposite arguments. And yes, my common functionality includes UI handling. – Centurion May 24 '15 at 08:46
  • Since you want static cells, I don't think it should be very hard to just use a ViewController, pop in a scrollview, and make basic calculations to position each of the cells. Honestly it shouldn't be hard at all, and it can inherit from your VC class. Strict UITableView static cells isn't possible in code unless you pop in an array to pull titles out of. Static cells are meant for storyboards and xibs. – Schemetrical May 24 '15 at 08:52
  • @Schemetrical I'm already using ViewController+scrollView for such of the screens. But it would be interesting to workaround UITableView static cells restriction, because probably we need to implement several methods on our own. Currently I'm stuck on cellForRow and numberOfRows because tableView asks for them but should grab those cells out from interface builder (xib). – Centurion May 24 '15 at 09:01
  • `UITableViewController` so far is the only way I've found working that doesn't call `-numberOfRows:` and `-cellForRowAtIndexPath:` with static cells. I think that's the only difference between implementing your own `UITableView` and using the standard `UITableViewController`. – Schemetrical May 24 '15 at 09:05
  • @Centurion Could you just have a storyboard with a single table view controller, which you instantiate with `instantiateInitialViewController`, and embed that programmatically in your custom view controller? The storyboard is then just a XIB by another name. Alternatively, have you looked at [this solution](http://stackoverflow.com/a/13728293/3985749)? – pbasdf May 24 '15 at 13:03
  • @pbasdf thanks. Regarding storyboards, there only acceptable way for me to use them would be to replace them 1:1 with xibs. That means having 1 storyboard for each of the screen. I don't like async nature of prepareForSegue: method which doesn't allow to use custom designated initializer and pass needed params into presented controller right away on the second line where controller is created, however, I could live with that :) What would you personally think of think of this approach if targeting big apps with multiple devs? – Centurion May 24 '15 at 13:36
  • I wouldn't want to encourage you down the line of replacing all your XIBs with single-controller-Storyboards. That seems to be a bridge too far. And I am a one-man band with no multiple developer worries, so personally I live with the complications of storyboards. But I was hoping you might live with this TVC being an exceptional storyboard in an otherwise XIB based project. Also, with storyboards you don't have to use segues - once you instantiate a storyboard VC in code, you can just present/push it same as any other VC. So you can avoid the async `prepareForSegue` hassle. – pbasdf May 24 '15 at 13:57
  • @pbasdf Yes, but you need to pass params to presented controllers and perform dependency injection (for unit tests) for which I usually use custom designated initializers. Therefore we are forced to use prepareForSegue when working with storyboards for passing params. – Centurion May 24 '15 at 14:02
  • Yes, sorry, I missed that point. Sorry to waste your time. – pbasdf May 24 '15 at 14:12

1 Answers1

1

Static cells need a UITableViewController. You can't changed this right now.

But to use static cells in a UITableView outside of a UITableViewController you can use a ContainerView in your Non-Table-UIViewController, where you place a real, separate created UITableViewController working with those static cells.

To share common code between multiple view controllers, inheritance is not that best solution as you found out by yourself while subclassing UIViewController vs. UITableViewController. You can use some sort of composition for sharing code or - especially for objective-c - categories.

Categories are not allowed to have its own properties, but there are workarounds possible with objc_setAssociatedObject.

Another approach would be to not use static cells, but dynamic cells in a UITableView with DataSource-Delegate :)

As you see in my screenshot, to reuse a special TableView with static cells, i place it in other ViewControllers in a ContainerView. Since you are not using storyboards, i am pretty sure that this can also be done by code without storyboard.

enter image description here

itinance
  • 11,711
  • 7
  • 58
  • 98
  • I agree regarding composition, however as I wrote in the comment, you may know very granular decomposition over complicates the code and sometimes is not necessary. All of my common code is already decoupled into separate classes and accessed via interfaces, however viewController UI specific common code nicely sits inside these BaseViewControllers. There wouldn't be any real benefit of forcing to change that. Meanwhile I'm more concerned about mass storyboard euphoria because it really brakes separation of concerns and clean MVC approach and introduces unnecessary merge conflicts. – Centurion May 24 '15 at 09:07
  • yes, storyboards can really mess up, especially when more then one person is working at it. Exactly your case, that it is impossible to reuse custom UIViewController-Subclasses also with UITableViewController, prevents me to do subclassing here. My Databindings comes from DataModels based on ReactiveCocoa, so i had no need to have huge ViewControllers. Indeed, they are pretty small – itinance May 24 '15 at 11:51
  • In case you would be interested to leave a comment, I'v started to push my open source template based project generator framework (https://github.com/GitTennis/SuccessFramework/tree/master/Templates/_BusinessApp_) which implements all these things I'm talking about. I thought about ReactiveCocoa, though I usually try to avoid using KVO, maybe because of too much broadcasted notifications which flood stack trace and makes hard to debug. Instead I use old-school type of separation of Models and DataObjects and do view-model bindings manually. Anyway, a lot of different ways how to go.. – Centurion May 24 '15 at 13:18