Swift: Make UIViewController print off the subclass type upon hitting the viewWillAppear or viewWillDisappear functions? - swift

The title basically asks my question for me. I have a number of view controllers which I'm loading in or dismissing as a user goes through the app. I'm having some asynchrony issues with the dismiss calls being called potentially too much. It's been a bit of a doozy going through the code base and finding what is being called where. I'd like to just print off whenever a new UIViewController hits the points in it's lifecycle functions viewWillAppear() or viewWillDisappear(). Is there a way for me to extent the UIViewController in such a way that all of its subclasses will naturally do this? Or would I have to go through each subclass to add in that code?
Thank you!

You could create a new UIViewController base class with the following:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("\(type(of: self)) will appear")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("\(type(of: self)) will disappear")
}
You'll have to inherit from this class on any view controller whos events you want to log

Related

viewDidDisappear not showing ad

Im using startApp to display ads but when the view disappears it doesn't show the ad. I have startAppAd = STAStartAppAd() in viewDidLoad() I'm not quite sure what is going wrong.
override func viewDidAppear(_ animated: Bool) {
startAppAd?.load()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
startAppAd?.show()
}
viewDidDisappear is called when the vc is about to dimiss or popped , so any property is in it's way to deallocate if that vc is not strongly linked , so move the show method also inside viewDidAppear or in the ad load finish callback if any

self.tabBarController.selectedIndex not calling viewDidAppear

I've been looking at and trying all the solutions others have posted to this problem, but I'm still not getting it.
My use case is very simple. I have a viewController with a button, when that button is pressed I want to navigate to another tab and reload the data including an api call.
When using the button, I navigate to the tab fine, but viewDidAppear is not being called.
If on another tab, and navigate using the tab bar, viewDidAppear works fine. Also viewWillAppear is working, but I have to add a manual delay to the functions I want to call so it's not ideal.
So what do I need to do to navigate using self.tabBarController.selectedIndex = 0 and get the functionality of viewDidAppear?
Update: The viewWillAppear method I added gets called but I have to add a delay to my functions in order for them to work, and it's a bit clunky, not ideal. Not sure why viewDidAppear will not work :(
Here is a screenshot of the structure:
I appreciate any help on this one!
The "current" ViewController is my tab index 2:
import UIKit
class PostPreviewVC: UIViewController {
//Here I create a post object and post it to the timeline with the below button
#IBAction func postButtonPressed(_ sender: Any) {
//create the post via Firebase api
self.tabBarController?.selectedIndex = 0
}
}
In my destination viewController:
import UIKit
import Firebase
import SDWebImage
import AVFoundation
class HomeVC: UIViewController {
// MARK: - PROPERTIES
var posts = [Post]()
let refreshControl = UIRefreshControl()
//more properties...
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
configureTableView()
reloadTimeline()
UserFirebase.timeline { (posts) in
self.posts = posts
self.tableView.reloadData()
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear")
_ = self.view
setupUI()
configureTableView()
reloadTimeline()
UserFirebase.timeline { (posts) in
self.posts = posts
self.tableView.reloadData()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewWillAppear")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.reloadTimeline()
self.configureTableView()
}
}
//All the tableview code below here...
}
Added a custom class for my tab bar controller:
import UIKit
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear in tabBar custom Class called")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear in tabBar custom Class called")
}
}
When you are using UITabBarController, the method viewDidLoad will called only once when any UIViewController is loaded in memory. After that, when you are navigating the same UIViewController, then it will load from memory.
In order to overcome this problem, you must divide your code in viewDidLoad & viewDidAppear. So, in viewDidLoad, you only put that code which you want to intialize once throughout the app such as adding UIView's or other things, while in viewDidAppear / viewWillAppear, you can make API calls or some functions which fetches dynamic data.
Finally, when you are calling self.tabBarController.selectedIndex = 0, it will call viewDidLoad only once and viewDidAppear / viewWillAppear every time when you are navigating that UIViewController.
Hope this helps to understand like how UITabBarController works.
For UITabBarController viewDidLoad only gets called once. and your viewWillAppear and viewDidAppear get called multiple times. you can either check if your viewWillAppear gets called or not. because your view will appear gets called before your viewDidAppear it's just like going through the reverse engineering process.
You can also add viewDidAppear method into your UITabBarController custom class. and call its superclass method into it in that way I think it will solve your problem.
Note: In the case of UITabbarController, Always do your UI update task and API calling a task in either
viewWillAppear or viewDidAppear

Subclassing UITableViewController to be subclassed again in Swift

I'm wanting to make a subclass of UITableViewController that has some specific functions in it. That way when I make a TableViewController in the storyboard I can just subclass this new class I made.
But when I try to replace UITableViewController with my new class, I get errors about not having viewDidLoad() function or any of the other lifecycle functions.
Here is my subclass of UITableViewController:
class TutorialTVC: UITableViewController {
var tutorialTab: TutorialTab?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tutorialTab?.dropDownTab()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.tutorialTab?.pullUpTab(0.2)
}
func createTutorialTab(segueNameOnOpen: String) {
self.tutorialTab = TutorialTab(sourceVC: self, putTabBelowView: nil, segueNameOnOpen: segueNameOnOpen)
}
}
As you can see, I tried adding in the override for viewDidLoad(), but even then is states this:
Method does not override any method from its superclass.
I thought that when you subclass something, all of it's functions are brought in as well... Or is there additional code I need to add to make this happen. I'm pretty new to subclassing like this.
My guess is you didn't import UIKit in this file. However you can create your class as subClass of UITableViewController right from the interface as below,
This will handle import of UIKit. Also it will add all the essential methods to start with TableViewController.

How to Stop a VCs functions from operating when VC is not in view? [Swift 3.0 Xcode]

I have a view controller which contains functions wish I need to disable once I leave the view controller. The functions wont start until I navigate to the VC, which is what I want, but I also what these functions to stop once I leave and navigate to other view controllers. Does anyone know any tricks to this?
there are multiple ways you can do this.
One like others have commented is invalidate timers or location stuff in either one of these methods.
let someTimer = Timer()
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
someTimer.invalidate()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
someTimer.invalidate()
}

How to open the keyboard automatically on UITextField?

I have a very simple table and when tocuh a cell it opens a new view with one UITextfield. All I want is that the keyboard will automatically opens, without the user have to touch the UITextfield.
Its all done in Interface Builder, so I am not sure how I do this. I guess I need to set the focus at some point ?
Thanks
To cause the keyboard to show up immediately you'll need to set the text field as the first responder using the following line:
[textField becomeFirstResponder];
You may want to place this in the viewDidAppear: method.
Swift 3 & 4:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
textField.becomeFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
textField.becomeFirstResponder()
}
Prefer adding the first responder on the main thread -
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.textField.becomeFirstResponder()
}
This will come in handy when the view controller view is added as a subview.