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
Related
I have a UIView which I am using as a seperate module and can include it anywhere I want to. Now I want to navigate to a UIViewController on click of the button inside the UIView.
Hope this is pretty clear.
Short answer: You shouldn't. You need to read up on the MVC design pattern. A UIView is a view object. You are trying to add controller behavior to a view object.
You should take a look at parent/child view controllers, container views, and embed segues. You could easily create a view controller that manages a "tile" inside another view controller, and sends messages to it's parent when the user taps buttons. This is a very common way of doing things.
The best way to do this is to supply the ViewController to the view as a delegate, conforming to a protocol you create for it.
For instance, if you UIView is used to pick an image, then the delegate should have a method akin to:
(void)view:(UIView*)view choseImage:(UIImage*)image;
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.
I need to implement an accordion control for iOS. By accordion, I mean a UI like this:
I see two basic ways to do this, but I'm not sure which one to choose.
Method #1: Create a ViewController container, something like a UITabBarController, except that instead of showing tabs at the bottom, I draw a vertical stack of buttons, and when you tap one, the corresponding panel opens and shows the corresponding view controller's view.
Method #2: Create a composite view, add a bunch of views directly to it, and show/hide them as needed.
How do I choose here? What would make me want to treat the sub-units as view controllers vs views?
Generally speaking, if I can avoid it I try not to subclass UIView and instead do everything within UIViewController subclasses. A controller is usually required anyway (model/view glue code, user interaction, delegate stuff, notification handling, etc.), so if no custom drawing is needed it is usually possible to do without a UIView subclass.
In your case I could envision one reusable UIViewController subclass that represents a list entry. It has the following responsibilities:
Create two alternate view hierarchies (collapsed/button, expanded/panel)
Toggle between the view hierarchies in reaction to user interaction (with/without animation)
And another UIViewController subclass that represents the entire list. It has the following responsibilities:
Override the appropriate methods from UIViewController to make it into a container VC
Add/remove child VCs as appropriate to the internal model
Possibly adjust the container view in reaction to collapse/expand events in its child VCs
What I want
I want to add some logging code into my app without having to update all of my view controllers.
What I've tried
I attempted to add a category to UIViewController and override one of the delegate methods. However, this produced several warnings/errors.
Is there a way for me to inject code into all of my app's ViewControllers?
Look into method swizzling. It is a powerful tool and can save you a lot of time. Swizzle one of the methods you wish to have logs in, and then call the original method to have it do what it is originally supposed to.
You could subclass UIViewController and then add the logging methods in your super class. You would still need to touch all of your VC's though and change the class to your super class though.
You can't possibly have so many view controller classes in an iOS app that touching each one will be a huge problem. So create your own UIViewController subclass, maybe OurSuperViewController that'll act as a superclass for your view controllers, and add the logging there. Then modify each of your view controller classes so that they inherit from OurSuperViewController, and make sure that each one calls super in the relevant view controller methods.
Once you've done that, you can turn logging on or off at will by modifying just OurSuperViewController.
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.