I've a UITabBarController with two tabs. In each tab there is a table, and in the viewWillAppear I load the data and reload the table:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tableView.delegate = self
tableView.dataSource = self
loadTasks()
}
func loadTasks(){
let url = Api.GET_TASK_USER_MONTH
Task.getTasks(url) { tasks in
if !tasks.isEmpty {
for index in 0...tasks.count-1 {
self.tasks.append(tasks[index])
}
}
self.tableView.reloadData()
}
}
But every time I switch between the tables the data displayed is wrong. It fires displays the second's tab data, then it displays OK the first one and then it displays the one's data all the time in the two views.
Any ideas?
UPDATED: My loadTasks() method.
Normally viewWillAppear should be called if you "enter" the tab.
It might be the case that the ViewController gets not deinitialized => the ViewController is still there and therefore viewWillAppear will not be called.
You might need to use a weak self in loadTasks:
func loadTasks(){
let url = Api.GET_TASK_USER_MONTH
Task.getTasks(url) { [weak self] tasks in
if !tasks.isEmpty {
for index in 0...tasks.count-1 {
self?.tasks.append(tasks[index])
}
}
self?.tableView.reloadData()
}
}
Related
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?
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()
I'm trying to show a UITableView from a button, I tried 2 different ways:
One by showing by a UIStackView with was hidden from the beginning, and just show with "isHidden", another way with a view from another UIViewController, which is called with "didMove(toParentViewController: self)"
With both ways, the tableview is showing instantly, but to hide it again, that's taking forever.
I've tried to put the "isHidden = true" in "DispatchQueue.main.sync" to use the main thread, but still not working as I would like...
Any suggestions?
Here is some code of my application :
#IBAction func ProfilPicture1Pressed(_ sender: UIButton) {
let popUpTeamDog = storyboard?.instantiateViewController(withIdentifier: "selectTeamDogPopUp") as! SelectTeamDogPopUp
DispatchQueue.global().async(execute: {
DispatchQueue.main.sync{
self.addChildViewController(popUpTeamDog)
popUpTeamDog.view.frame = self.view.frame
self.view.addSubview(popUpTeamDog.view)
popUpTeamDog.didMove(toParentViewController: self)
}
})
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dog: Dog
if(searching){
dog = searchArray[indexPath.row]
} else {
dog = dogs[indexPath.row]
}
let nameDog = dog.name
//let imgDog = UIImage(named: dog.image)
print(nameDog)
DispatchQueue.global().async(execute: {
DispatchQueue.main.sync{
self.view.removeFromSuperview()
}
})
So I can add that when I click on the searchBar, then select a dog, the tableView / View disappear instantly, so when the keyboard is activate, that's working well... Stranger things....
Your code uses main thread by default. So you don't have to use this DispatchQueue.global() and DispatchQueue.main. It's too slow.
So replace this
DispatchQueue.global().async(execute: {
DispatchQueue.main.sync{
self.addChildViewController(popUpTeamDog)
popUpTeamDog.view.frame = self.view.frame
self.view.addSubview(popUpTeamDog.view)
popUpTeamDog.didMove(toParentViewController: self)
}
})
with
self.addChildViewController(popUpTeamDog)
popUpTeamDog.view.frame = self.view.frame
self.view.addSubview(popUpTeamDog.view)
popUpTeamDog.didMove(toParentViewController: self)
and do the same with self.view.removeFromSuperview(). Replace this
DispatchQueue.global().async(execute: {
DispatchQueue.main.sync{
self.view.removeFromSuperview()
}
})
with
self.view.removeFromSuperview()
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
}
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
}
}