Reuse identical delegate methods in multiple controllers? - ios

I have a UITextFieldDelegate method shouldChangeCharactersInRange that is exactly the same across several view controllers, so I had to just copy-paste it into every view controller that conforms to the UITextFieldDelegate. I like sticking to DRY, and here I have identical code in lots of view controllers. Is it possible to reuse delegate methods and what are good ways to do it, or this is the only/optimal way and why?

Create a sub class of UIViewController which implements just the delegate methods you wish. Set this as the parent class of all the view controllers in your project which want the delegate methods to be used.
Instead of that, you can also try looking into Categories. Create a category on UIViewController named whatever you wish. Add the delegate methods you wish to implement to this category. Now, all view controllers in which you #import this category will implement the delegate methods.

You can make a parent object class from which all your view controllers inherit. Place the delegate method code in the parent object implementation.

You can create an object that conforms to UITextFieldDelegate and inherits from NSObject.
Then, on each view controller you can create an instance of this object, storing it on a property and assigning your UITextField's delegate to this object.

Related

Connecting Objects with two View controllers in Swift

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.

move tableview delegates to different class

I have one view controller containing lots of operations. Most of the views are created dynamically. To separate out code I created a class as a myClass of NSObject where I created a function showMyTableView. This function adds a tableview as subview. but I have to write all tableview delegates inside view controller. How I can move require delegates to myclass?
Tomorrow I may require to add subview containing buttons for which I should write action in separate class.
How I can accomplish same?
your new class should handle data only, not ui.
for different table cellview consider use separate tableviewcell subclasses and provide them data models. let them configure themselves
(By 'table view delegates', I assume you mean your table view's delegate and dataSource?)
You can certainly move this stuff to another class. You would simply set the delegate/dataSource of your table view to an instance of MyClass, in your view controller, like so:
self.tableView.delegate = instanceOfMyClass;
MyClass probably shouldn't be responsible for creating the table view and adding it to your view controller's view though. Your view controller should be responsible for this itself.

Objective-C: Inject code into delegate method

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.

Should [super loadView] be called from loadView or not?

In Programming iOS 4 by Matt Newburg he states:
“To provide a UIViewController with a view manually, implement its
loadView method… You must NOT call super”.
In the iOS 5 Developer's Cookbook by Erica Sadun she states:
“The loadView method allows you to set up the screen and layout any
subviews… Make sure to call [super loadView] whenever you inherit
from a specialized subclass such as UITableViewController or
UITabBarController.”
This, to me at least, is confusing.
Apple is the source of truth and they say NO super call.
If you override this method in order to create your views manually,
you should do so and assign the root view of your hierarchy to the
view property. (The views you create should be unique instances and
should not be shared with any other view controller object.) Your
custom implementation of this method should not call super.
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621454-loadview
[edit]
Another important note scattered around in the UIViewController class reference:
The default loadView method attempts to load the view from the nib
file associated with the view controller (if any).
This is a very old question, but I find that it needs a better answer than the one it got.
Should [super loadView] be called from loadView or not?
It depends. The two sources you cite are talking about different situations, and they're both correct in the context they're describing.
The quote from Neuberg is talking about view controllers that inherit directly from UIViewController. That class has its own implementation of loadView that provides default behavior; specifically, it automatically loads the view hierarchy from a .xib (or storyboard) file that's associated with the view controller. If you call UIViewController's version of that method, the view hierarchy created in that method will either replace your own implementation's view hierarchy, or vice versa. Nine years after this question was posed, the documentation for UIViewController's -loadView method still warns against that:
You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super. [emphasis added]
The quote from Sadun is talking about a different situation, i.e. one in which your view controller is not a direct subclass of UIViewController, but is instead derived from UITableViewController, UITabBarController, etc. Those classes override -loadView themselves and need their versions called. At least in the case of UITableViewController, this is called out in the Overview section:
You may override loadView or any other superclass method, but if you do, be sure to invoke the superclass implementation of the method, usually as the first method call.
So, if you're subclassing UIViewController and providing your own -loadView implementation to generate the controller's views rather than using a .xib or storyboard to provide the views, don't call the superclass's -loadView method. On the other hand, if you're subclassing a class such as UITableView and doing the same thing, check the docs to see whether you need to call that class's -loadView method from your own override.

Passing data over views

I have a navigation based view and the data entered in a view that is lower down in the hierarchy is then to be shown in a table-view in the root-view. How do I pass data entered in a subview to a superview??
There is several ways to do that.
You can create a singleton class which provide data to your UIViewControllers: Creating a Singleton Instance
Or you can use UINavigationControllerDelegate Protocol which include method called before and after UIViewController push.

Resources