iOS tableView not reloading until click, scroll, or switch tabbar items - ios

I have this problem where (in several places) after executing an API call, the view does not refresh until a user action - like a btn click, tab bar switch, etc occurs. I have a feeling it is related to threading, but I can't seem to figure it out and I am new to iOS programming. I have tried different solutions with DispatchQueue etc, using it, and not using it. Trying to call setNeedsDisplay on the controller view. But no luck yet. The following is an example of code pulled right from one of my tab bar item view controllers:
func getEmployeeUpdates(){
self.showLoader()
APIAdaptor.shared.getEmployeeUpdates(forEmployee: Session.shared.employee, completion: {
(updates:[ScheduleUpdate]?, error:Error?) in
guard error == nil else{
DispatchQueue.main.async {
// self.resetMainScreen()
self.hideLoader();
}
return
}
DispatchQueue.main.async {
self.hideLoader();
self.ScheduleUpdates = updates!
self.tableView.reloadData();
}
})
}
func showLoader(){
NSLayoutConstraint.activate([
activityIndicator!.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor),
activityIndicator!.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor)])
activityIndicator?.startAnimating();
}
func hideLoader(){
print("Hiding");
activityIndicator?.stopAnimating()
}
I have attached two images. The first image is where the api call has finished (confirmed through testing) but the view is not refreshing. The loader is frozen. It should disappear after a call to hideLoader(). the second Image is after a click, or tab bar item switch.
I should also mention that in this example, as well as in other api calls the view will refresh eventually after completing, but only after a significant delay.
If anyone can help I would appreciate it very much!

This was a problem caused by the simulator on Xcode 10.1. If you run into this problem, try updating Xcode, or using a real device.

Related

how to prevent button showing up for split second when view loads

So my goal is to smoothly load the viewController with no split second bugs. I have a function that is used to determine what buttons to show when the view loads based off a field in a Firestore document. Here is the function:
func determinePurchasedStatusVerification() {
db.collection("student_users/\(user?.uid)/events_bought").whereField("event_name", isEqualTo: selectedEventName!).whereField("isEventPurchased", isEqualTo: true).getDocuments { (querySnapshot, error) in
if let error = error {
print("\(error)")
} else {
guard let querySnap = querySnapshot?.isEmpty else { return }
if querySnap == true {
self.purchaseTicketButton.isHidden = false
self.viewPurchaseButton.isHidden = true
self.cancelPurchaseButton.isHidden = true
} else {
self.purchaseTicketButton.isHidden = true
self.viewPurchaseButton.isHidden = false
self.cancelPurchaseButton.isHidden = false
}
}
}
}
I call this function in the viewWillAppear() of the vc but when I instantiate to that vc, this is the result...
The extra purchase ticket button shows up for a split second. Even though it's very quick, you can still see it and it's just not something a user would need to see. It's also the other way around when you click on a cell that's not purchased, the two bottom buttons show up for a split second. I just want to know how I can prevent this quick bug and be able to display a smooth segue with no delays in the button hiding. Thanks.
getDocuments is an asynchronous function, meaning it doesn't call its callback function immediately -- it calls it when it gets data back from the server. It may seem like a split second just because your internet connection is fast and the Firebase servers are definitely fast, but it's a non-zero time for sure. And, someone with a slower connection might experience much more of a delay.
Unless your callback is getting called twice with different results (which seems doubtful), the only solution here is to make sure that your initial state has all of the buttons hidden (and maybe a loading indicator) and then show the buttons that you want once you get the data back (as you are right now). My guess is, though, that you have an initial state where the buttons are visible, which causes the flicker.

Refresh Control Issue with custom cells - Swift 4 IOS 11

I am building an iOS app and I am trying to implement a pull-down refresh control on my project. The data is fetched correctly from an API and displayed on my table. But the problem rises when I do pull down to refresh. The following situations happen:
If I pull down for a long distance from the top, and the tableview.reloadData() function is called, the cells in the non-visible portion of the table come with the default tableview cells on top of them, overlapping...
if I pull down multiple times in quick succession the same issue happens.
I believe that it is because tableview.reloadData() is called multiple times in quick succession. But why are the default cells getting dequeued on top of my custom cells? Here is the section of code in the function to handle the pulldown:
#objc func refreshFunc(){
//let offset = scrollView.contentOffset.y
if myRefreshControl.isRefreshing{
readJson { (activities) in
self.activities = activities
self.tableView.reloadData()
self.myRefreshControl.endRefreshing()
}
}
}
Any help would be appreciated. Thanks in advance
UPDATE:
Changing the code to the code below seems to remove the error, but the problem is that now I need to pull down twice in order to get the results updated on the table:
#objc func refreshFunc(){
readJson { (activities) in
self.activities = activities
}
self.tableView.reloadData()
self.myRefreshControl.endRefreshing()
}
Please note that running the reloadData on the main thread gives the same result, I still need to pull down twice to update.
Please try to give some delay before refresh table view may it resolve your problem.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayTime) { [weak self] in
self?.tableView.reloadData()
}
Hope it works
Cheers :)
DispatchQueue.main.async {
self.tableView.reloadData
}
Try this, always, if u want change UI you have to call on main thread

ios status bar with strange behaviour

Using iOS-9.2 and Swift-2.1:
Getting back to my rootViewController using the below code, unfortunately leads to a very strange behaviour of the status-bar of my App !
static func returnToRootViewController(sender: AnyObject) {
let initialscene = sender.storyboard?!.instantiateInitialViewController()
for _ in sender.view!!.window!.subviews {
sender.dismissViewControllerAnimated(true, completion: nil)
}
sender.view!!.window!.rootViewController = initialscene
}
The two images below show the status bar in its normal condition (i.e. left image) and after returning by above returnToRootViewController-Code (i.e right image with strange coloring) !
Prior to applying the above code, the navigation-controller was navigated to severeal modal popovers....
Any help on this appreciated !
You're dismissing the same viewcontroller several times. Calling dismissViewController will only dismiss the one presented by the sender, not the several underneath it (I'm assuming sender is the topmost one)
From this answer, it sounds like you might be able to dismiss all of them just by dismissing the first one presented by your rootViewController: https://stackoverflow.com/a/23566262/78496

Missing Navigation's or Back Button's Title When Push ViewControllers in Succession

I have a problem on UINavigationController when pushing view controllers in succession.
For information, I use XCode 7.0, build targeting iOS 8, and the app running on Simulator 9.0.
Here's the view when user manually tap the tableview's cell:
As shown on the above screenshots, the navigation's and back button's title were rendered normally.
But when I did this programmatically, like this (stack is array of UIViewController):
for controller in stack {
self.mainNavController.pushViewController(controller, animated: false)
}
or using delay on 0.0 second like this:
for controller in stack {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64((0.0 * Float(NSEC_PER_SEC)))), dispatch_get_main_queue(), {
self.mainNavController.pushViewController(controller, animated: false)
})
}
It will show the final result like this (left is w/o delay, right is w/ delay):
Notice the missing navigation title on the left screenshot (w/o delay) and missing back button title on the right screenshot (w/ delay).
This issue has confuse me for days. Any idea of why this is happening? Does anyone know how to fix this? Or at least, work around this issue?
Thanks in advance.
This is what I have done in the past. You might find it helpful:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let myBackButton = UIBarButtonItem()
myBackButton.title = "This is my back button"
navigationItem.backBarButtonItem = myBackButton
}
This is happening because the intermediate view controllers are not being told to load so it isn't able to load things properly like the correct messaging for the back button. For any intermediate viewControllers, call loadViewIfNeeded() and then the upper view controllers can get all the required info from them.

View get unhide automatically in iOS

I have created a view on interface & reducing its height on click of a button with uianimation.Below is the code for the animation
#IBAction func filterClick(sender: AnyObject) {
STF_Search.resignFirstResponder()
UIView.animateWithDuration(0.3, animations:{
if(self.isFilter==false){
self.filterView.frame=CGRectMake(0,117,self.view.frame.size.width,50)
self.STVRA.frame=CGRectMake(0, 168,self.STVRA.frame.size.width,self.STVRA.frame.size.height)
self.isFilter=true
}
else{
self.filterView.frame=CGRectMake(0,117,self.view.frame.size.width,0)
self.tableView.frame=CGRectMake(0, 117,self.STVRA.frame.size.width,self.STVRA.frame.size.height)
self.dateTo="nil"
self.dateFrom="nil"
self.isControlls(true)
self.isFilter=false
}
}
,completion: {(_) -> Void in
if(self.isFilter==true){
self.isControlls(false)
}
else{
self.callRAListWebApi()
}
})
}
Code working perfectly if I don't call the method "self.callRAListWebApi()" on the other hand in above scenario when execution of this methods complete the "filterView" gets into its default height-> 50 which is not supposed as per the logic it should be "0"
("callRAListWebApi" is a method where I am hitting a web api & getting some json response)
I cant understand this unusual behaviour of "filter view" of coming in its original height.I have checked everything there is no clue.
Create autolayout of the view , as the problem is because you are directly changing the frames.

Resources