In my project I have two view controllers, and I am having trouble connecting objects such as an UIImageView to the view controller. When I try to create the IBOutlet, it tells me that "Could not insert new outlet collection: could not find any information for the class named UIViewController". I believe this problem stems from the fact that my original declaration of my class is as follows:
class UIViewController: UIViewController {
when in fact the view controller is named mainScene instead. However, when I change the first UIViewController to what I think it should be (mainScene), it doesn't even show me the option of connecting an IBOutlet...
class mainScene: UIViewController {
So, I have two questions.
Do I need to have a whole separate class for the second UIViewController and would that solve my issues?
Is there a better way to link objects to the UIViewController or am I just doing something horribly wrong (the likely scenario)?
Thanks so much
Short answer: 1. Yes, and yes. 2. There's no better way, and you're not doing something horribly wrong. (You probably just missed a step.)
You have two view controllers. Assuming they are different, you would subclass each one from UIViewController with a different name. E.g., mainSceneViewController and otherSceneViewController.
Your mainSceneViewController and otherSceneViewController would each have their own properties and IBOutlets.
Where you're probably stuck, is needing to change the class of your viewController within Interface Builder to match the class name in its .swift file, so IB knows what outlets it can connect for that view controller.
Each scene in your storyboard corresponds to a view controller. When the segue is performed, iOS instantiates your view controller from the storyboard.
While it is possible to only have one view controller subclass, and use the same subclass for different views, it doesn't happen too often.
Update:
Subclassing lets you add properties and methods to a class, and override their superclass.
In your comment, UIViewController is the class, and mainSceneViewController is subclassed from UIViewController. For your second view controller, it would likely be class otherSceneViewController: UIViewController {, as your other scene would likely require a different properties and methods from your main scene view controller.
You can read more about Inheritance in the Swift Programming Language guide.
Related
I'm new to iOS development and this could be a stupid question for some experienced guys...
When I create a new iOS project in Xcode, I get a ViewController class and a storyboard which sets its Custom Class to this ViewController. It looks like there is a "Storyboard" class holding an instance of ViewController, however, I cannot find where this "Storyboard" class is defined.
Even though I know how to create multiple subclasses of UIViewController to handle different views interaction following some tutorials, I still find it uncomfortable to associate these subclasses to the storyboard by selecting them in the storyboard panel. I would rather see something like a "Storyboard" class holding an array of UIViewController.
So my question is, how these UIViewController interact with the Storyboard under the hood?
Thanks
Roughly, it happens as follows:
App launches.
App loads storryboard.
Depending on app's navigation structure, app instantiates each view controller inside the storyboard as needed.
The storyboard contains detailed information on:
Which custom subclass of UIViewController, UINavigtionController, etc. to use for instantiating each view controller in the storyboard.
How to map (connect) each if its view controllers' subviews to the corresponding custom classes' outlets and actions.
But seriously, read Apple's docs. It's all there.
UIViewController has a property named storyboard which refers to the storyboard file associated with the viewcontroller subclass.
Also the view controller code are interecting with the storyboard with connections symboled with #IBOutlet and #IBAction.
I am writing a simple app with custom storyboards for iPhone and iPad. I have a generic viewcontroller class from which my custom iPhone and iPad viewcontrollers inherit. Outlets and IBActions in my storyboards are mostly wired up to the generic viewController class and everything works well.
Now for stylistic reasons I decided to make my iPhone's viewcontroller be a UITableViewController and it can no longer inherit from my generic viewcontroller. I've been googling and searching this site and see advice which says I should write a category and use this in my custom classes.
I have never done this, but I looked at the documentation and understand the concept, but once I move my code into a category, how would I be able to link my storyboard's outlets and actions (ctrl-drag from storyboard) to the methods which are now moved out of my custom viewcontroller classes? Usually I would for example ctrl-drag from a switch in the storyboard to an existing IBAction method in my generic viewController, but these methods will now be inherited and not showing my my custom classes to drag to.
I am just a hobbyist and newb, so I apologize if this question is too basic.
You can use UIViewController with UITableView instead of UITableViewController.
1.In storyboard, get a new UIViewController and linking with your custom viewcontroller class.After that,put an UITableView into that UIViewController and linking with that class using (ctrl-drag from storyboard) called mTableView
2.In that class you should implement <UITabBarControllerDelegate,UITableViewDataSource>.
Use mTableView instead of self.tableView just like in UITableViewController.
Sometimes I want to subclass UIViewController for some app wide customizations. Eg. something that all view controllers should perform during viewDidLoad or viewWillAppear or so.
Naturally I subclass UIViewController and go from there and all view controllers inherit from that. But some of the controllers run tables. And there is UITableViewController designed for that purpose.
So I subclass UITableViewController too and just do the same things there. Which does not seem to be the smartest thing in OOP terms. And there is no multiple inheritance etc.
And as UITableViewController inherits from UIViewController ...
Now I am asking myself why I don't just create my own table view controller that inherits from my very own view controller subclass and adds all the table stuff. But what is "all the table stuff"?
There is the skeleton code that xcode adds to every new table view controller. Quite handy but that can be easily moved to code snippets.
There is the declaration of the protocols UITableViewDelegate and UITableViewDataSource. Easy going. The implementation of those methods has to follow in each subclass of UITableViewController anyway.
There are probably reasonable default implementations of all those mandatory methods in the protocol. Such as returning 0 for numberOfSectionsInTableView: or nil for titleForHeaderInSection or 44.0f for heightForRowAtIndexPath: (Bad example though. Could be smarter not implementing that at all)
So despite the obvious stuff, are there any miracles that UITableViewController takes care of?
I believe all of the behavior UITableViewController adds is well defined in the class documentation: https://developer.apple.com/documentation/uikit/uitableviewcontroller?language=objc
The UITableViewController class creates a controller object that manages a table view. It implements the following behavior:
• If a nib file is specified via the initWithNibName:bundle: method (which is declared by the superclass UIViewController), UITableViewController loads the table view archived in the nib file. Otherwise, it creates an unconfigured UITableView object with the correct dimensions and autoresize mask. You can access this view through the tableView property.
• If a nib file containing the table view is loaded, the data source and delegate become those objects defined in the nib file (if any). If no nib file is specified or if the nib file defines no data source or delegate, UITableViewController sets the data source and the delegate of the table view to self.
• When the table view is about to appear the first time it’s loaded, the table-view controller reloads the table view’s data. It also clears its selection (with or without animation, depending on the request) every time the table view is displayed. The UITableViewController class implements this in the superclass method viewWillAppear:. You can disable this behavior by changing the value in the clearsSelectionOnViewWillAppear property.
• When the table view has appeared, the controller flashes the table view’s scroll indicators. The UITableViewController class implements this in the superclass method viewDidAppear:.
• It implements the superclass method setEditing:animated: so that if a user taps an Edit|Done button in the navigation bar, the controller toggles the edit mode of the table.
All of these are behaviors which should be easy to re-implement if they apply to your specific controller and table view.
In general I have found it preferable to implement these behaviors myself in order to allow for alternate inheritance hierarchies as you noted and because I usually consider setting both the delagate and datasource of a table view to be a view controller a design smell. Those are independent concerns which usually can and should be handled by some other class (e.g. a dedicated data source for a particular model class) rather than bloating a view controller.
So despite the obvious stuff, are there any miracles that UITableViewController takes care of?
Not that I am aware of. As far as I know UITableViewController is mostly a convenience class that can be replaced with your own subclass that adds a few lines of code.
Apple's class documentation pretty much says all that UITableViewController does (and I'm not repeating that here because it may well change in the future). Sometimes, additional information can be gleaned from a class' header file, but in the case of UITableViewController.h the source code comments just repeat what is already in the class docs.
In the end you must decide yourself what you want to replicate in your own subclass. Maybe your project does not need .nib handling? Or none of your table views is editable? So just don't code that...
It seems that the UITableViewController takes care of a lot of management issues that really you could just do for yourself, if you wanted to. Check out the documentation -- it will automatically create a UITableView for you, reload it, etc.
I have 30+ viewcontroller in my project, and there is a behavior to be added in 28 of them.
When a button is clicked if 10 second not passed in that viewcontroller, I need to present a alertview sliding from top. (I have already implemented this behaviour for one of them)
But my question is, how can I inherit this behavior in a proper way for all of these viewcontrollers?
Googling this, but cannot find relavent solutions.
If all of your view controllers that need this functionality are subclasses of UIViewController, i.e. not UITableViewController or another subclass of UIViewController, you can create a subclass of UIViewController, say ButtonClickAlertViewController (or whatever makes sense) that implements the functionality you need to replicate. Then have all of the classes that need this functionality subclass your ButtonClickAlertViewController class instead of UIViewController.
You may need to take into account how this specific functionality integrates into each of your individual view controller classes. For example, you may need a method in your ButtonClickAlertViewController class that signals a button has been clicked in order to check your timer and possibly display an alert. In each of your classes that subclass ButtonClickAlertViewController, you might need to call this method in each of the IBAction methods that your button click actions call.
Subclass UIViewController and add your desired behavior for all view controllers and then subclass your existing view controllers from the viewController with the desired behavior.
Inheritance chain:
UIViewController -> ViewControllerWithBehaviorForAll ->
YouExistingViewlContollersWhichNeedTheBehavior
In my app, I wanted to show a table in the "full screen," so I created a subclass of UITableViewController. When I want to show the table, I just instantiate it and use pushViewController:animated:. Now I've decided that I actually want to show it as a modal, so I want to give it a navigation bar with a "Done" button. I believe this means that I now need to make this a UIViewController subclass instead of a UITableViewController subclass, since it will now be more than just a table. I'm not really sure if this is something that can be done, though; I've created an xib, but Xcode doesn't seem to want to let me use that xib to create IBOutlets in the .h file, so I don't think the two are "connected."
I ran into this problem once before and worked around it by just creating a new UIViewController subclass and xib and just copy-and-pasting all the stuff I needed from the UITableViewController subclass's files into the new subclass's files. I knew then as I know now that that was a hacky and unpleasant solution, though. Does anyone know how something like this can be done properly?
Also, to avoid this problem in the future, should I just never make top-level views like this in the future and just make sure everything I use pushViewController:animated: or presentModalViewController:animated: with is a UIViewController subclass? Or is it safe to do what I've been doing?
Several things you mention in your question indicate some misunderstandings. First, if you're pushing you table view controller, then it has to be embedded in a navigation controller, and thus will have a navigation bar -- you can add a done button to this bar, if that's all you're trying to change. No need to refactor your code.
If you want to use a UIViewController instead of a table view controller, you should be able to hook up your nib. Did you change the class of the files owner in the nib to your UIViewController class? After you do that, you should be able to hook up the outlets.
There's nothing "hacky" about copying and pasting code from a table view controller into a view controller. I do this all the time, rather than writing out all those files.
I'm not sure what you're asking in the last question. How you get your table view on the screen (pushing or presenting) has nothing to do with whether what you're showing is a table view controller or a view controller. You should use the one that best fits your needs.