Pull to refresh view not dismissing when used to trigger a segue - ios

I want to use a pull-to-refresh UI action to trigger a segue to a modal view. The action works fine, triggering the modal segue as expected. But when I dismiss the modal, the refresh control view is still visible.
I am correctly calling refreshControl.endRefreshing() before the segue, but the problem seems to be that the UI doesn't have time to complete the animation that dismisses the refresh control view before the segue is trigger, so it gets suck half way.
If I place a small delay (0.4s) before triggering the segue this kind of helps, as it allows the animation to complete, but it feels like a hack. Also, if the user pulls down really slowly on the tableview, and releases the pull-down later than after 0.4 seconds, the same problem occurs.
How can I ensure that the refresh control will not be visible when I dismiss the modal view? Ideas I have (but which I can't find a way to implement) include:
1) ensuring the animation that dismisses the refresh control has time to complete before the segue is triggered.
2) dismiss the refresh control view on the parent view when I dismiss the modal.
I can't get either of the above to work though.
With 1) a delay works (sometimes), but feels like a hack.
With 2) tableView.reloadData() only reloads the tableview, not the whole view, so the refresh control remains.
Any help would be greatly appreciated.
Here is the code that implements the refresh control.
lazy var refreshControl: UIRefreshControl = {
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(pullToAddCard(_:)), for: .valueChanged)
return refreshControl
}()
And here is the code that gets triggered by the refresh control
#objc func pullToAddCard(_ refreshControl: UIRefreshControl) {
refreshControl.endRefreshing()
delay(0.4, closure: {
self.performSegue(withIdentifier: "segueFromPlaylistDetailToNewCard", sender: self)
})
}
And here is a screenshot of what the parent view looks like when I nav back to it (by dismissing the modal view.) The 'stuck' refresh control view is visible at the top.

Just add
refreshControl?.endRefreshing()
to your viewWillAppear method
I just tried the following using the storyboard below, and it works fineā€¦
class TableViewController: UITableViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
refreshControl?.endRefreshing()
}
#IBAction func unwind(sender: UIStoryboardSegue) {
}
}

Ok, I found a solution. #Ashley Mills' answer gave me an idea. In viewWillAppear I call refreshControl.beginRefreshing(), and then immediately call refreshControl.endRefreshing(), and that works!
For some reason, simply calling refreshControl.endRefreshing() wasn't enough.

Related

Avoiding Delay from One View Controller to Another in Xcode using Swift

I have set up a button in my iOS App that performs segue from 1st View Controller to 2nd View Controller. But, there is a delay of about 3-5 seconds on moving from 1st View Controller to 2nd View Controller. Is there any way by which this delay can be avoided and the user can easily go to the 2nd View Controller on the click of the button without any delay? Would appreciate it if anyone could provide any suggestions on how can I eliminate this issue? Thanks a lot for the help:)
#IBAction func startButton(_ sender: Any) {
performSegue(withIdentifier: "1to2segue", sender: self)
}
The 2nd View Controller displays live stats extracted from an external source. Thus, it takes time to load up. How can I make this process faster?
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
In your second view controller, do NOT call your loadData() func in viewDidLoad().
You want to do as little as needed to get the view on the screen. Show a spinner or some other "Loading Data..." activity view.
Then, perhaps in viewDidAppear(), call your loadData() func. But make sure whatever you're doing in loadData() is being done in an async process.

How to automatically reload the data from viewcontroller?

I am trying to find the solution for how to automatically reload all the data in view controller but i can't find any. Right now i am using push to refresh to reload the button/title/data in view controller viewDidload() but i want to have it automalliy reload everything every time i come back to this viewcontroller. For example when app lunched, it load view controller A then i clicked on the button to go View controller B but i want to controller A to refresh everything after back from B so how can i do that?
Thanks
For this, there is a method viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadData()
}
func reloadData() {
//All you need to update
}

how to check if a view controller appeared after some other page in navigation controller pressed back button?

I'm in detailViewController and when I press back button, it goes to mainViewController. How can it be determined in mainViewController that it was not freshly loaded but the back button was pressed in detailViewController?
There is a table which I want to reload in mainViewController and hence I'm trying to determine if it was loaded freshly or coming from detailViewController. Any help would be greatly appreciated and up voted. Thank you.
Override the viewWillAppear() function in your mainViewController to execute tasks before loading it.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated: animated)
//do tasks when coming from detailViewController
}
EDIT:
There is another way if you don't want the code in viewWillAppear to ecexute upon fresh load, but i don't know if it's the best thing to do. In your back button handler do the following:
//pop the detailViewController
self.navigationController.popViewControllerAnimated(true)
//mainViewController is now at the top
//safely unpack it
if let parentVC = self.navigationController.topViewController as? mainViewController {
//call a custom function in mainViewController which will
//execute only the stuff you want upon back button press
parentVC.customFunction()
}

Back Bar Button Segue hides Toolbar

I am using a Show segue in my application.
Whenever I segue to another screen and press the back bar button, my navigationController.toolbar disappears.
I tried to get rid of it with
navigationController?.toolbar.hidden = false
in my viewDidLoad().
It doesn't work though. Any ideas?
Please add the code in the viewWillAppear() and it should solve the problem you are facing.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.toolbarHidden = false
}
Remember that viewDidLoad() fires only once during the life cycle of a view controller and in your case , it is in the navigation stack which means it has been already used for that view controller and now when you press back button, it does not work again.
navigationController?.toolbarHidden = false

performSegueWithIdentifier is being skipped *SWIFT

I have a UITableViewController that I would like people to access as the main page. I do have a login view controller but I do not want this to be my initial view controller. I have an if statement checking if the user has logged in previously. If not, I would like to perform a segue to the login view controller. When I run the app however, it goes through the if statement, recognizes that the user is == nil, and then goes right over the performSegueWithIdentifier operation.
override func viewDidLoad() {
super.viewDidLoad()
if user == nil {
self.performSegueWithIdentifier("LoginSegue", sender: self)
}
}
Any idea why?
You should move your code into the viewWillAppear or viewDidAppear method.
Then it should use properly.
But now the view flickers a short time. To remove that flickering, just hide the view in your viewWillApear method:
self.view.hidden = true
Also the viewDidLoad method doesn't get called everytime the view appears but only the first time it loads. If you for example perform a segue and return back to the view, it doesn't load again but only calls viewWillAppear and viewDidAppear again.
For Swift 3.0, try to run on the main thread like this.
DispatchQueue.main.async {
self.performSegue(withIdentifier: "LoginSegue", sender: self)
}
Without more information it is hard to say.
Do you have a button or something with an already established segue, and have you provided the identifier for the segue? I made a similar call in viewDidLoad and it worked.
Have you embedded the view controller in a UINavigationController? If not, performing the segue is not possible. It sounds like you're using a UITableViewController, which inherits from UIViewController. So this may be the issue.
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewController:UIViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ViewControllerClassId") as! ViewControllerClassName
self.presentViewController(viewController, animated: true, completion: nil)
})
this code solved my problem.
use my code instead of
self.performSegueWithIdentifier("LoginSegue", sender: self)
and give your destination ViewController an ID like ViewControllerClassId

Resources