Need to call super constructor for lifecycle methods in Swift - ios

I've been coding for some years now, and I'm very used to always calling a method's super constructor when overriding it. But recently I've been wondering if it's always necessary... I get that when you override an initialiser you should call super.init(). But in Swift and iOS development, if you override a UIViewController lifecycle method like viewDidLoad() and forget to call super.viewDidLoad(), the compiler dosen't produce any warning or error and the code seems to be compiling fine. So I was wondering if the call is somehow build into the SDK, and if it's even necessary to make (with in mind that we want to make the code as efficient and correct as possible)?

I think you may look here a nice answer.
Apple doesn't restrict you to call super.viewDidLoad(), but it won't be safe to use some view cycle methods and variable before it's call. If you want first to init your own vars or properties for example - I think, it won't be a problem.

Yes, you should always call super.
Here is what I do alwyas
// MARK: - Controller life cycle stack
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
setupNavigationBar()
}
override func viewDidAppear(animated: Bool)
{
super.viewDidAppear(animated)
}

So, after a while I experienced first hand what might happen if I did not always call super:
Let's say you have two viewControllers
class ViewControllerA: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.doSomethingImportant()
}
}
class ViewControllerB: ViewControllerA {
override func viewDidLoad() {
self.doSomethingLessImportant()
}
}
Now you expect that when you push to ViewControllerA it'll call doSomethingImportant(), but in most cases that will not happen, because you forgot to call super.viewDidLoad() in ViewControllerA.

Related

Call extension function IOS Swift

How can I call extension function, so that the button is encouraged to call the view.
I made a UiButton Extension with a function to animate a button, and everything works, but only if I call it from:
#IBAction func botonVuelta(_ sender: UIButton) {
sender.pulsarAnimacion()
}
but if you called it from viewDidLoad it doesn’t work:
override func viewDidLoad() {
super.viewDidLoad()
botones.layer.cornerRadius = 20
botones.pulsarAnimacion()
}
I’d appreciate it if you could give me a solution,
I thank you in advance
viewDidLoad is a very early place to animate a view , try inside
override func viewDidAppear(_ animated:bool) {
super.viewDidAppear(animated)
botones.pulsarAnimacion()
}

In inheritance can we by pass viewDidLoad

I have a UIViewController_A.
I this view controller's vidDidLoad I have a http request for getting some data.
I inherited UIViewController_A and created UIViewController_B.
Now can I bypass the [super viewdDidLoad]; in UIViewController_B.
Because if I call [super viewdDidLoad]; in xxx_B then it is making http call from xxx_A, and I don't want this.
viewDidLoad() method should always call super.viewDidLoad(). Not doing it may cause the controller to not instantiate correctly.
Instead, you can override the desired behaviour of the parent controller. For example:
class ParentController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
performOperation()
}
func performOperation() {
print("Calling WebService from ParentController")
}
}
class ChildController: ParentController {
override func viewDidLoad() {
super.viewDidLoad() // <--- ALWAYS REQUIRED
// Custom initialization
}
override func performOperation() {
print("Overriding parent operation so it doesn't call the WebService")
}
}

Storing input from field as variable with swift 3

I realize this question has been asked numerous times before, but I can't quite get the solutions to work, even by just copying and pasting them, and suspect that most swift documentation spans the three versions since swift's release.
I'm attempting to do something as simple as storing a variable from a field input and not having much luck.
import UIKit
class ViewController: UIViewController {
#IBOutlet var userNumber: UILabel!
#IBOutlet var userField: UITextField!
#IBAction func userButton(_ sender: UIButton) {
let userInput = userField.text
//some action
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You should check whether you have set your textfield's delegate with respect to parent view controller.
Go to storyboard.
Select textfield.
Right click on it.
set delegate from textfield to view controller

Why viewDidLayoutSubviews is called twice only on first run?

It's driving me crazy this. Only on first run the viewDidLayoutSubviews is called twice.
Here is the code I'm using:
class CICViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func addQLabel(qLabel: UILabel, questionString: String, bgrLabel: UILabel) {// some code goes here
}
func makeRoundQButtons(qButtons:[UIButton]) {
// some code goes here
}
func addArrows(numberOfArrows:Int, buttonCurAngle:Double) {//some code goes here
}
func animateButtons(qButtons:[UIButton], buttonCurAngle:Double) {
// some code goes here
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
func backTapped(sender: UIBarButtonItem) {
navigationController?.popViewControllerAnimated(false)
//some code goes here
}
func restartTapped(sender: UIBarButtonItem) {
navigationController?.popToRootViewControllerAnimated(false)
//some code goes here
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
And in my ViewController I call this :
class OneViewController: CICViewController {
override func viewDidLoad() {
super.viewDidLoad()
//some code goes here
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("viewDidLayoutSubviews")
self.makeRoundQButtons(qButtons)
self.animateButtons(qButtons, buttonCurAngle: 2.0)
}
override func viewDidAppear(animated: Bool) {
//nothing goes here
}
}
There is no guarantee as for how many times viewDidLayoutSubviews will be called.
You can find a great discussion in this Stack Overflow post:
When is layoutSubviews called?
I found this article useful. A summary from what it says:
init does not cause layoutSubviews to be called (duh)
addSubview causes layoutSubviews to be called on the view being added, the view it’s being added to (target view), and all the subviews of the target view
setFrame intelligently calls layoutSubviews on the view having it’s frame set only if the size parameter of the frame is different
scrolling a UIScrollView causes layoutSubviews to be called on the scrollView, and it’s superview
rotating a device only calls layoutSubview on the parent view (the responding viewControllers primary view)
removeFromSuperview – layoutSubviews is called on superview only (not show in table)

IOS Swift - Passing data between view controllers using container view

I am a little confused on how to use container views correctly, i will try to explain it the best i can.
I have a main view controller that has an animation function.
import UIKit
class MainViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate {
// Run view setups
override func viewDidLoad() {
super.viewDidLoad()
}
func closePicker(){
self.view.layoutIfNeeded();
UIView.animateWithDuration(0.5, animations: {
self.countryPickerConst.constant = -206;
self.view.layoutIfNeeded();
})
}
}
In interface builder i have added a container view with a new view controller that contains a button like so:
import UIKit
class ContainerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func runAnimation(sender: UIButton) {
//I want to call the function in my other view controller
}
}
In the action runAnimation i want to call the function in the MainViewController. If i just create an instance of MainViewController and call the function it seems to loose its 'self' relevance.
If someone could explain to me the best practice for doing things like this that would be great.
Thanks
From your explanation MainViewController is the parent of ContainerViewController so to access closePicker from ContainerViewController you would do:
#IBAction func runAnimation(sender: UIButton) {
(self.parentViewController as! MainViewController).closePicker()
}

Resources