Omit [super] call when overriding view events in UIViewController. Impact? [duplicate] - ios

This question already has answers here:
What is meaning of calling superview's viewwillappear?
(3 answers)
Closed 9 years ago.
What happens if you don't call super in your implementation of the view events (viewWillAppear, viewDidAppear etc.) of UIViewController?
It seems like I've forgotten to do this before, and it's unclear to me that there was any adverse impacts.

If you subclass one of your own view controller classes, you will certainly want to call super for any of these types of methods or your own base class's methods will not be invoked.
There's also the question of whether your top-level view controller classes need to call super to run the code in the base UIViewController class itself. In the UIViewController reference, it appears that the requirement to call super is documented for certain methods, among them viewWillAppear:, viewDidAppear, viewWillDisappear:, and viewDidDisappear:
If you override this method, you must call super at some point in your implementation.
However, there is no indication of what will happen if you fail to do so.
So apparently, there is something implemented in these methods in the base iOS framework view controller classes. Or at least, Apple reserves the option to implement something in these methods. You could say that they are virtual rather than abstract methods.

If you've subclassed your UIViewController delegate from anywhere (and you always subclass UIViewController at least once, in making your customized view controller), then any delegate methods in subclasses you've derived from won't get called.

Related

Does implementing UIResponder touch methods inside a UIView subclass violate MVC?

The following UIResponder methods report raw touches on screen:
- touchesBegan:withEvent:
- touchesMoved:withEvent:
- touchesEnded:withEvent:
Recently I was playing with a UIView subclass that I wanted to be touch responsive.
Initially I implemented the methods above in the UIViewController that was responsible for the view in question.
However, I realised that the touch methods were being called whenever the UIViewControllers view was being touched, not the subview I wanted.
I reimplemented the methods inside a UIView subclass and everything worked as expected.
However I feel like this is violating MVC. I have control logic inside my view.
Should I keep the methods implemented inside the UIViewController instead, and somehow hit test to interpret which view was touched, or am I correct in having the methods implemented inside the UIView subClass?
I feel like the later is the lazy way out.
Thanks for your time.
In MVC, the view is responsible for user interaction. Therefore, it makes more sense to have your UIResponder methods overridden in your UIView. To keep strictly with MVC, you should then use a delegate pattern (or some other pattern) to call control logic functions that are in your controller.
The above image is from (Apple's MVC documentation). The part that pertains to your question is in the upper left. The view should tell the controller it has been touched ect, and the controller should execute the logic.
The UIViewController only is able to implement these methods because it comes with a built in view. This is confusing because it means that the UIViewController itself violates MVC, but thats a more involved discussion.

iOS Swift how to monitor UIViewController lifecyle

I am new to iOS development. So pardon me if this is a very basic thing.
From what I have learnt till now:
UIViewController class resembles somewhat equivalent to an Activity class in Android.
and viewDidLoad/viewWillAppear method to onCreate/onStart method
and viewDidAppear method to onResume method
Please correct me if I am wrong here.
Now, in Android we can monitor which of these methods(including other lifecycle methods) are triggered/called by implementing an Interface (ActivityLifecycleCallbacks) (somewhat resembling a protocol in iOS) which exists in the Application class in any Activity (particularly in a class which extends Application class).
It means that now these methods will be triggered/called whenever there is any navigation from one screen to another in the android app.
How do I do this in iOS using Swift? How do I know which screen(UIViewcontroller) the user is currently in and where he is navigating?
In short I want to write a standalone class which logs which screen(UIViewController) the user is currently in and which one of the lifecycle methods(viewDidLoad, viewWillAppear etc) is being executed?
Someone please help me out.
Edit:- I don't want them to subclass my standalone class instead of UIViewController class.
There are no global events that are fired when the UIViewController lifecycle methods are called. To create those you would need to subclass UIViewController as has been suggested.
You can look at UIApplication.sharedApplication().keyWindow?.rootViewController to get the current root view controller (which is often, but not always the currently active view controller).
You wouldn't typically design an app that depended on some central object tracking the state of view controllers.
The flow of UIViewController methods is pretty well described in the class reference and you can also work it out from the function names -
viewDidLoad called after the view controller instance is loaded (once per instantiation)
viewWillAppear called before this view appears
viewDidAppear called after this view appears
viewWillDisappear called before this view disappears
viewDidDisappear called after this view disappears
Create a view controller subclass and add that implementation in there. Then make sure all the view controllers you create subclass that new class rather than UIViewController 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.

What happens if I write touches event for a View in its View Controller?

I have seen Code snippets where people have written touchesBegan and touchesEnded in the View Controller of a view.
I am relatively new to iOS development and am unable to understand how is that possible.
Aren't these methods of UIView class that we override in our custom views.
and If its possible then If I call view's touches Event which version gets the priority ?
The one in the View controller or one in the View itself.
As you can easily look up in the documentation, the touches...:withEvent: family of methods is declared in the UIResponder class. Since both UIView and UIViewController inherit from UIResponder, both classes have access to the methods and can override them.
As to the question which implementation gets priority if both are implemented, that is defined by the responder chain. Touch events travel up the responder chain until they find an object that wants to handle the event. Since a view is placed before its view controller in the responder chain, the implementation in the view class would be executed.
The view controller has copies of these methods as well. It's for convenience so you don't have to create a custom UIView subclass just to handle touch interaction.
If both the view and the view controller implement these methods then they both get called when the user touches the screen, however I believe that the ones on the view get called first.
Note that as of iOS 3.2/4.0, UIGestureRecognizers are generally a much easier way to do most types of touch interaction. There's rarely any need to use touchesBegan and touchesEnded any more.

Resources