swift reload views when value changed - ios

I have some views.
A MainViewController with 6 buttons.
Here every button would start a function.
A tableview with 6 cells and each cells open an other ButtonVC. ( FirstButtonVC, Second... )
In every ButtonVC there is a picker.
There is an option in the picker ( it says -- ) which is basically nil so it will disable the button on the main VC.
My problem is that when I set it to this disabled option, or even if i enable a button with the picker, in the MainVC the button's ui won't refresh only after stopping and starting the application again in the simulator.
S my question is:
How can I refresh the MainViewController's ui from the ButtonVC so when the user returns to the MainViewController he can already see the updated ui with the updated buttons?
I hope my question is understandable.

The best way to approach this problem is by solving UI updates in the
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Add you code here
}
Of your MainViewController.

Related

iOS Swift Segmented control with container view for switching - views are not loading first time

I've followed this tut https://spin.atomicobject.com/2015/09/02/switch-container-views/ to create a segmented controller with two container views.
My problem is that the when app is launched first view is not shown. Clicking on second segment also doesn't do anything.
Only after third clicks and onwards these views are loaded.
It's strange as I've downloaded the code in tut and it works perfectly fine but it doesn't work when I create my own project and follow exactly same steps as shown in above tut.
Can anyone point me what I might be missing?
See the attached screenshot. When I run the app First segment is the default segment but in the view below it loads second segment.
Next when I click in Second it doesn't do anything.
Only after third click and onwards it loads correct segments.
You can try added this code after method viewDidLoad, for show animation after app loaded.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animateWithDuration(0.5, animations: {
self.containerViewA.alpha = 1
self.containerViewB.alpha = 0
}
}

Prevent keyboard from dismissing while changing views

On apps like say the stock messages app, if you’re in a conversation with the keyboard showing and swipe to go back to your conversation list, the keyboard remains up as the view gets swiped away.
I can’t seem to figure out how to mimic this behavior but I’ve seen it in other apps so it’s gotta be possible.
Edit: Not sure I understand why this is getting downvotes. It’s definitely a valid question where I couldn’t find the answer on google?
Edit 2: Here’s a video of what I’m trying to accomplish https://arxius.io/v/a555c8db compared to this behavior in discord https://arxius.io/v/0bfda09a
On apps like say the stock messages app, if you’re in a conversation with the keyboard showing and swipe to go back to your conversation list, the keyboard remains up as the view gets swiped away.
I don't actually see that behavior, at least in the Messages app on an iPhone. That said, the keyboard should remain visible whenever the first responder can accept text. If you want to switch to a different view controller and keep the keyboard visible, then make sure that first responder in the new view graph is editable. For example, if there's a text field, you could set it to be the first responder.
So before we talk about any kind of solution, let's learn exactly why the keyboard is dismissed.
As you know, iOS UI works on a view controller based system, with a text field ultimately being managed by a view controller somewhere.
When you click the back button, the active view controller is released from the navigation stack and therefore the system deduces that the text field is no longer in use, so it resigns it as the first responder.
Unfortunately there is no built in way to alter this behaviour and whilst we can speculate how apple might do it, we do not know.
The few options we have are not particularly neat or tidy, but a method I have had success with in the past is creating a hidden text field directly on the window before you pop the view controller and setting it first responder. Then on your other view controller, the text field can take first responder from the invisible one and remove it.
This is not ideal, but it's the only technique that comes to mind.
It is correct that you had to have UITextFiled available for both views to have keyboard passed between them consistently. But nobody said that this textfield had to be on screen, or had to be part of ViewController's view.
So all you had to do is to place this textFiled somewhere out of screen, for example as subview of your window, or NavigationController's view, make it first responder, and switch to your text field on view didAppear:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.textField.becomeFirstResponder()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
let fixedView = self.view.window
let fakeTextField = fixedView?.subviews.last as? UITextField ?? UITextField()
fakeTextField.autocapitalizationType = textField.autocapitalizationType
fakeTextField.autocorrectionType = textField.autocorrectionType
fakeTextField.center = CGPoint(x: -100, y: -100)
fixedView?.addSubview(fakeTextField)
fakeTextField.becomeFirstResponder()
}
Make sure that keyboard configuration is the same, otherwise you will have it switching.

Delay when using instantiateViewControllerWithIdentifier but not performSegueWithIdentifier?

The code below is used to push another view controller onto the navigation stack.
When using instantiateViewControllerWithIdentifier, the segue is noticeably sluggish the first time (~3 seconds) but occurs reasonably fast each subsequent time. Other SO posts suggested ensuring the segue occurs on the main thread, which the code accomplishes, but this didn't fix the problem.
However, using performSegueWithIdentifier causes no delay.
The viewDidLoad code for SendViewController is the same for the first and subsequent pushes.
Tried blanking out viewDidLoad for the destination view controller, but still the lag exists for instantiateViewControllerWithIdentifier but not for performSegueWithIdentifier.
How to fix the delay with instantiateViewControllerWithIdentifier?
No delay:
#IBAction func buttonTapped(sender: UIButton) {
performSegueWithIdentifier(SendSegue, sender: self)
}
Results in delay when showing SendViewController for first time:
#IBAction func buttonTapped(sender: UIButton) {
dispatch_async(dispatch_get_main_queue()) {
let vc = self.storyboard!.instantiateViewControllerWithIdentifier(self.SendViewControllerID) as! SendViewController
self.navigationController!.pushViewController(vc, animated: true)
}
}
This issue could occur in many different scenarios. The best way determine what is causing your specific problem is by profiling with the instruments included in Xcode.
Click and hold the Build button in your xcode window. You will see four options appear, select Profile.
Once the build runs a window with instruments will pop up. Select, Time Profiling from the options.
A new window will appear with various metrics in it. The top left corner will have a red record button. Click the red record button and this will launch the app on your phone.
Proceed to the transition giving you problems. End the recording after the transition occurs by selecting the same button you started the recording with.
Review the "Details" pane in the bottom left corner. You will see a column titled "Running time" that shows the time it took to execute every method in your code (both OS methods and user generated code)
Determine if anything is out of place or occurs that is not intended. Possibly go back and execute the transition again to compare the difference between the two. Clicking the function in the list will take you directly to the code being executed. This can be very helpful.
It is very likely that if a transition takes 3-5 seconds one particular function will be obvious when following these steps. Happy profiling!
WWDC from last year has a great segment on this as well. Def worth checking out here: (open in Safari only) WWDC Profiling Talk
The problem was isolated to the presence of a UITextField in the destination view controller, that is, removing the UITextField removes the lag.
Then it was further isolated to the presence of a custom font.
In other words, using the system font on the UITextField, rather than a custom font, removes the lag. No explanation why, but it works.
After time profiling I realized it was the call to instantiateViewController which I couldn't find anything that could help me with that.
Unfortunately, the only thing that worked was either using a separate storyboard for that view controller and instantiating it from there, or redoing the view controller programmatically.

How to set VoiceOver initial focus on a UITableView

In our iOS app, we have a screen with a UINavigationController, three UIBarButtonItem in the rightBarButtonItems, a UIView content view with a UITableView subview.
Every time the app gets to the foreground, VoiceOver places the initial focus on the leftmost UIBarButtonItem. We would like to have the focus on either the topmost cell in the UITableView (initial start) or the cell that the user actively selected before the app went to the background.
We have tried to call UIAccessibilityPostNotification() but this only works if we add a delay and that seems very fragile and will be confusing for the user as focus will start on the UIBarButtonItem and then jump.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.75*Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.view)
}
This might work.
As far as I know uiaccessibilitypostnotification works well with the delay, even though it is fragile, you can call the method with 0.5 seconds delay in the view did appear method!!!!
There is also another way you can try. Once the view is loaded, disable the accessibility for the bar buttons, and set the accessibility only for the tableview!!! You need to change the accessibilityElements array and the first element in the array should be the table view, and set isAccessibilityElemnt to NO for the other elements to turn off the accessibility!!!!

How to restart UIRefreshControl animation?

I have several tableviews in a tab bar controller. On some of these I have set a UIRefreshControl.
After swiping down to start a refresh the 'spinner' animation begins. If I select a different tab and then move back to the original tab, the refresh control is still shown but the animation has stopped.
How do I restart this animation?
I've tried starting the refresh again and got no results.
I also inspected the view hierarchy, hoping to find a UIActivityIndicatorView but could only find a _UIRefreshControlModernReplicatorView that seems to be the view doing the animation. I don't know of any method I can call of this to get the animation restarted.
I had a similar problem, although not exactly the same problem as described in the original question.
The issue: When I moved from a screen with a tableView with refresh control (not a UITableViewController) to a different one, then I found when I returned to the screen, the activity indicator portion of the refresh control was displaying (not animating) as an artifact just under the top of the table view.
I tried a lot of ideas (hiding the refresh control, ensuring endRefreshing was called, etc.) until I found something that actually worked:
In viewWillAppear(animated:), add the following:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.refreshControl = nil
tableView.refreshControl = refresher
}
Just adding that code fixed the issue for me. Your mileage may vary, but perhaps somebody will find this useful.

Resources