Skip swift ViewController main functions such as viewDidDisappear - ios

In my code, when a view disappears, a specific action occurs. I am doing it through the viewDidDisappear() function.
I have a specific button that when is pressed it goes to another view. I was wondering in what I way I could tell ONLY the function caused by a specific button to skip the viewDidDisappear().
I perfectly know I can add a sort of 'if' statement in the viewDidDisappear() but I was wondering if there was a more efficient method.

viewDidDisappear() is a UIViewController's lifecycle callback method that's called by the environment - as far as I know there is no way to disable its calling. And I don't think there should be - as I mentioned, it is a part of UIViewController's lifecycle, not calling it would break the contract - see its documentation.
Therefore you have to (and you should) achieve what you want by using if statement.
Do something like this:
fileprivate var skipDisappearingAnimation = false
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
prepareInterfaceForDisappearing()
}
fileprivate func prepareInterfaceForDisappearing() {
guard !skipDisappearingAnimation else {
// reset each time
skipDisappearingAnimation = false
return
}
// do the stuff you normally need
}
#objc fileprivate func buttonPressed(_ sender: UIButton) {
skipDisappearingAnimation = true
// navigate forward
}

It cannot be done; you must handle the case manually with if, something like:
var shouldSkip: Bool = false
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if !shouldSkip {
// your code goes here
}
shouldSkip = false // don't forget to set should skip to false again
}
#IBAction func buttonDidTap(_ sender: Any) {
shouldSkip = true // this will avoid run your code
// your code here
}

Related

how to check viewController is viewed for the first time in swift

I am running instruction framework at this link.
I am checking the application launched for the first time by this code:
func isFirstTimeOpening() -> Bool {
let defaults = UserDefaults.standard
if(defaults.integer(forKey: "hasRun") == 0) {
defaults.set(1, forKey: "hasRun")
return true
}
return false
}
I am calling it in viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if isFirstTimeOpening(){
self.startInstructions() //1
self.coachMarksController.dataSource = self //2
}
}
Here is my viewDidAppear function
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//if isFirstTimeOpening() {
self.coachMarksController.start(in: .window(over: self))
coachMarksController.delegate = self
// }
}
Second thing that i want to check for commented 1 & 2 is First viewController is Loading collectionView is viewed for the first time. This is because function func isFirstTimeOpening() -> Bool checks only application launched for the first time not viewController is visited multiple time during the first launch. I want to restrict these commands self.startInstructions() self.coachMarksController.dataSource = self to execute for first time viewed only(viewController having collectionView) ? How can do that?

How can I refresh or reload a WKwebview when selecting tabs

I have a tabbed app which loads separate internal file WKwebviews. I now need to have the WKwebview refresh when a tab is selected.
I think I need to add the required code in the viewWillAppear, but on trying to have some code on this method nothing works.
Does anyone have any suggestions as to how I can achieve this
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
webView.configuration.userContentController.add(self, name: "jsHandler")
let bundleURL = Bundle.main.resourceURL!.absoluteURL
let html = bundleURL.appendingPathComponent("main/index.html") //Loads internal HTML files
webView.loadFileURL(html, allowingReadAccessTo:bundleURL)
webView!.uiDelegate = self
webView.allowsBackForwardNavigationGestures = true //Allows 'safari' style gestures swipe back etc
}
override func viewWillAppear(_ animated: Bool) {
//Nothing
}
Update:
To resolve this, I added the above code into the viewDidAppear method rather than the viewDidLoad. This has resolved the problem.
The JS message handler still needs to be in the viewDidLoad.
Example:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
webView.configuration.userContentController.add(self, name: "jsHandler")
}
override func viewDidAppear(_ animated: Bool) {
//webView.configuration.userContentController.add(self, name: "jsHandler")
let bundleURL = Bundle.main.resourceURL!.absoluteURL
let html = bundleURL.appendingPathComponent("index.html") //Loads internal HTML files
webView.loadFileURL(html, allowingReadAccessTo:bundleURL)
webView!.uiDelegate = self
webView.allowsBackForwardNavigationGestures = true //Allows 'safari' style gestures swipe back etc
}
Try something like this on each tab action:
func reloadTabAction() {
if let url = webView.url {
webView.reload()
} else {
webView.load(URLRequest(url: originalURL))
}
}
We have reload property for WKWebView. So you can directly call the method.
You can call the method while tapped the tabView
Try the below code,
webView.reload()

Navigation Bar removeGestureRecognizer is not removing the Guesture

I need to add Tap Gesture on Navigation Bar or View.
I got the below solution which works perfectly fine.
But removeGestureRecognizer is not removing the gesture and it's breaking the functionality of other back buttons in other view controllers.
How to fix the issue?
var taskTodoOnBar : UITapGestureRecognizer!
override func viewWillAppear(animated: Bool)
{
navigationController?.view.addGestureRecognizer(taskTodoOnBar)
}
override func viewWillDisappear(animated: Bool)
{
navigationController?.view.removeGestureRecognizer(taskTodoOnBar)
}
Or
override func viewWillAppear(animated: Bool)
{
navigationController?.navigationBar.addGestureRecognizer(taskTodoOnBar)
}
override func viewWillDisappear(animated: Bool)
{
navigationController?.navigationBar.removeGestureRecognizer(taskTodoOnBar)
}
When I try to get gestureRecognizers count, It says nil. Then where is the gesture being added ?
override func viewWillDisappear(animated: Bool)
{
print(navigationController!.view.gestureRecognizers!.count)
print(navigationController!.navigationBar.gestureRecognizers!.count)
}
Try using this
Declared gesture as
let tapGesture : UITapGestureRecognizer = UITapGestureRecognizer()
Gesture Handler
#objc func tapHandler(handler: UITapGestureRecognizer){
print("gesture Added")
}
Added in Navigation bar as
override func viewDidLoad()
{
super.viewDidLoad()
tapGesture.numberOfTapsRequired = 1
tapGesture.addTarget(self, action: #selector(VC2.tapHandler(handler:)))
self.navigationController?.view.addGestureRecognizer(tapGesture)
}
Removed as
override func viewWillDisappear(_ animated: Bool) {
for gesture in (navigationController?.view.gestureRecognizers)! {
if gesture == tapGesture {
navigationController?.view.removeGestureRecognizer(tapGesture)
print("removed")
}
}
}
Updated Answer for - gesture count prints nil
console Output :
After help from iOS Geek, I figured out that, gestureRecognizers!.count was 2 in ViewdDidLoad but was nil inside viewWillDisappear.
Then I dug more and discovered that I had written the custom code for my back button.
So in such case, we Should removeGestureRecognizer before popToViewController
So this is for all whom I wish not to make mistake like me while using the custom back button.
func backBarBtnFnc(sender: UIBarButtonItem)
{
navigationController?.navigationBar.removeGestureRecognizer(taskTodoOnBar)
// CodTdo ...
self.navigationController!.popToViewController(VC2, animated: true)
}

What function to call to undo a change made in a UITextField?

In the shortcut bar of iOS virtual keyboard there is an undo button that undoes the editing. Is there a way to associate an arbitrary button to that function?
From iOS 8, shaking the device should trigger the undo operation. Your view controller should be the first responders so it can response to the undo trigger. You can have that by becoming the first responder one the view is about to appear and then resign it when it is about to disappear
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
becomeFirstResponder()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
resignFirstResponder()
}
override func canBecomeFirstResponder() -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
}
Here is the solution I implemented (the same can be done for the redo function).
import UIKit
class ViewController: UIViewController, UITextViewDelegate {
#IBAction func undoButtonPressed(sender: AnyObject) {
mainTextField.undoManager?.undo()
enableDisableUndoButton()
}
func enableDisableUndoButton() { // to disable or enable the button when needed
if mainTextField.undoManager?.canUndo == true {
undoButton.enabled = true
} else {
undoButton.enabled = false
}
}
func textViewDidChange(mainTextField: UITextView) { // monitors when user makes changes in the text field
enableDisableUndoRedoButtons()
}
}
To get undoManager to take notes of the text changes made via code on the field, I use this:
mainTextField.replaceRange((theRange), withText: newStr)

How to avoid viewWillAppear initially calling

I want to know something aboutViewWillAppear.I have a viewwillappar method for data refreshing. What I want to do is when this viewcontroller push from the previous one this refreshing should not be happen. (when initially loading this controller viewwillappear should not be call). Is this possible? If so how can I do that?
Please help me
Thanks
viewWillAppear will always be called when the view appears
You can use an instance variable to make sure it is not called the first time i.e.
#implmentation ViewController {
BOOL _firstLoad
}
- (void)viewDidLoad
{
[super viewDidLoad];
_firstLoad = YES;
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!_firstLoad) {
// do what you want to do when it is not the first load
}
_firstLoad = NO;
}
This is a example using swift 4.
var isLoadedFirstTime = false
override func viewDidLoad() {
super.viewDidLoad()
isLoadedFirstTime = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if !isLoadedFirstTime {
// Do what you want to do when it is not the first load
}
isLoadedFirstTime = false
}
[updated solution] The example using swift 5:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if !isMovingFromParent {
// Do what you want to do when it is not the first load
}
}

Resources