Xcode 12.0 iOS 13+ UIViewController() problem with viewWillDisappear() [duplicate] - ios

This question already has answers here:
Detecting sheet was dismissed on iOS 13
(13 answers)
Presenting modal in iOS 13 fullscreen
(27 answers)
Closed 2 years ago.
I have a simple flash card app I wrote for a friend of mine. I'm a hobby-est at best. It's essentially Tinder that you can flip the card over for a dead language. Everything has been working great up until the iOS 13 update with how Apple redid the Storyboards for flexibility.
My problem is my elegant solution to save userdefaults when exiting a view is no longer being called. This "carddeck" view controller is called when a button on another screen is pressed. To exit this same view controller before you would press a button that was tied to an "action segue - show" (not #IBAction) that would bring the view back to the "mainview" view controller. I tried the same action segue with "present modally." but no dice.
class CardDeckViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// called!
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
// called!
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
// not called when "return" on this screen is pressed;
// however, it still returns to the main screen it just doesn't save the user's score
}
Any help would be appreciated. My hope is there is an easier fix than redoing the entire storyboard. I see about UIModalPresentFullScreen. I'm no Swift guru so at this point I thought I would reach out to the pros. Hopefully this is too time consuming of a fix. Luckily I think the other views are not affected by this other than one more.
Thanks for reading!

A couple of things you might try:
It sounds like you're presenting the "main view" view controller again. Hard to tell without seeing your code but I think you should probably be dismissing "CardDeck" view controller in order to get back to your "main view" view controller.
Have a look at UIAdaptivePresentationControllerDelegate. This stackoverflow post covers the change and iOS 13 solution.
I had some similar issues with iOS 12 view controller lifecycle behavior being changed in iOS 13.
I suggest considering NotificationCenter if nothing else works. You broadcast from your current view controller and someone like your AppDelegate can receive the message and act on this. It's not always the best tool for the job but it can help in certain situations.
Not related to your question but your calls to super super.viewWillAppear(true) should probably be super.viewWillAppear(animated) so you're not disregarding the method argument.

The answer was at the bottom of this question:
Presenting modal in iOS 13 fullscreen
I just had to redefine the storyboard UI property from Automatic to Full Screen.

Related

TVOS UISearchController keyboard stopping to show

In my TvOS app I have a viewController with UISearchContainerViewController. Here is the tree of views:
and
The searchController looks good and work as needed. From this viewController I can go to another one and from there open another instance with initial viewController (with searchController). In this another instance the everything is well too. BUT, when i pop back to the first instance the keyboard disappearing and the tree looks like:
I think it's because the instance of the system keyboard is shared across the app. But i don't know how to fix that. Can you help me?
private var keyboardContainer: UISearchContainerViewController!
In initialController I did add
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
keyboardContainer.searchController.searchBar.becomeFirstResponder()
}
and it seems that fixed the issue.

How to present iOS keyboard along with the modal presentation of a ViewController?

I am building a pin entry viewController very similar to the iOS one you see when you go to Settings->TouchID and it prompts you for pin.
I am trying to mimic its behavior of presenting the iOS keyboard along with (at the same) of the modal presentation of the pin entry viewController. I have noticed other applications like Venmo are able to achieve this as well.
How can I achieve this behavior? My pinEntryView is a textField. I have tried sending it the becomeFirstResponder message in viewDidAppear, and this seems to work; however, it will present the iOS keyboard AFTER the viewController modal presentation has finished. I want the presentation to occur at the same time to give the feeling that the iOS keyboard is actually baked-in/part of the ViewController.
I have tried sending the becomeFirstResponder messages in viewWillAppear, viewWillLayoutSubviews as well, but these are not stable solutions. Sometimes the keyboard is displayed and sometimes its not. Is there anyway to do this?
I made the test by setting becomeFirstResponder in the viewDidLoad and it is working fine.
I have one button that calls the modal, and that modal has the next code:
override func viewDidLoad() {
super.viewDidLoad()
self.textField.becomeFirstResponder()
}
It has no unexpected behavior.
I believe I have had this issue before, and it has quite an interesting solution. What you want to do is call becomeFirstResponder in viewWillAppear before calling super 😱.
override func viewWillAppear(animated: Bool) {
textField.becomeFirstResponder()
super.viewWillAppear(animated)
}
Then when you call super the first responder is already set, and then iOS picks up this state and includes the keyboard appear animation in the appearance transaction.
Hopefully this can help you too.

presentViewController shows not all elements on presented view controller

I encountered a problem while trying to present a new view controller within a storyboard using following code:
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("ViewControllerIdentifier")
self.presentViewController(viewController!, animated: true, completion: nil)
The view controller does appear, but shows for some reason only two buttons, no other elements.
What have I tried so far:
Loading the view controller as initial view controller to see if the
problem remains.
No, all elements are at the right position.
Switching animated from true to false. Problem still remains
Printing the hidden attribute as well as x and y positions. Hidden
is false, and the positions are what they are supposed to be
Cleaning and rebuilding the project, since this seems to fix 99% of
all strange bugs based on my experience. Sadly this helped not this
time
Setting hidden first on true, then on false. Resetting the attribute
does not help.
Using CFRunLoopWakeUp(CFRunLoopGetCurrent()) . Does not help
either.
I have a simple drawing of what my view looks like attached.
As stated, the view controller is shown perfectly fine when I load it as initial view controller, but only the buttons are shown when using the code above.
ViewDidAppear is called as well.
I am using Xcode Version 7.2.1
EDIT:
As requested by comment, this is my code for the view controller to be presented:
import UIKit
class myViewController : UIViewController {
#IBOutlet weak var myImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
}
Edit:
I found a solution to this problem:
By creating the transition within the following block.
dispatch_async(dispatch_get_main_queue(),^{
});
It appears that my problem was, that the lines that trigger said transition weren't executed on the UI thread. I still have no idea why this lead to the behaviour explained above, but at least there is a solution.
In my experience problems like this can be down to your auto layout constraints being messed up or not quite as you need them (although the fact that it presents correctly when it is the default might suggest I am not headed down the right path).
Are there any warnings in the storyboard editor that suggest the constraints are not correct? I would also suggesting using the view debugging feature to help troubleshoot. Click on the circled icon when your app is running to show your view hierarchy and then try to find the views you think should be there. It also allows you to look at constraints, so that might help with point 1 above as well.

Xcode 7 - Some segues not working anymore

I upgraded my Swift app to Xcode 7 / Swift 2.0 and now suddenly certain segues in my app no longer work.
I have a segue popping up a "Check In" modal and it works perfectly, but then I have another segue popping up a "Check Out" modal that's near identical and it doesn't launch and the app is frozen.
I re-created the segue from scratch, confirmed that it is identical to the "Check In" one, and it still doesn't work.
I also, instead, tried launching a blank view instead of my Check Out modal and it works fine.
There are no errors, it just freezes, I did confirm that the "prepareForSegue" portion is being called correctly but the "viewDidLoad" portion of my modal is not being invoked.
FYI, I have auto-layout turned off.
Does your "Check Out" modal have a UITextView? If it does, then there's a bug in Xcode 7 / iOS9 where you cannot launch a modal (or any root view) that contains a UITextView if you have set a default text value in storyboard.
A work around is to make sure your UITextView in storyboard is either blank or has the default Lorem Ipsem value and instead, set the text programmatically in code on viewDidLoad.
Hopefully this bug will be fixed soon.
I suspect there is infinite loop somewhere in you "Check Out" controller code. Try pausing app in debugger after presenting controller (when it freezes) and check stacktrace. If it doesn't help, try commenting-out code line-by-line in viewDidLoad and viewWillAppear to find line causing freeze.
I had this problem, try with this
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("Storyboard Id")
self.presentViewController(viewController, animated: true, completion: nil)
})
You just have to give a storyboard id in your view and normally it's working.
My app was working perfectly in iOS8. Its flow was:
VC: View Controller, NVC: Navigation View Controller, ER: Embedded root relationship between NVC and VC, PS: Push Segue, PG: Programmatic presentation
NVC1---(ER)->VC1---(PS)->NVC2---(ER)->VC2 and so on.
The problem was that VC1-(PS)->NVC2 segue did not work, there was no freeze. vc1.prepareForSegue() was executed, but VC2 was not presented. I experimented and found that I did not have the UITextView problem mentioned here.
By following the breadcrumbs outlined below, I got it work after hours of trying in the following way (code at the end):
NVC1---(ER)->VC1---(PG)->VC2
Here are the steps:
As mentioned in Segue issue in iOS9, multiple NVCs are out of style (shame on Apple for suddenly ditching what is actually recommended in your online tutorial and making apps break!). So I modified
NVC1---(ER)->VC1--(PS)->VC2 while VC2 was still embedded in NVC2. I got errors
similar to the StackOverflow post on view not in hierarchy. So I started doing the transition programmatically and after tackling present vs. push ViewController issue that results in "tried to push modally on active view controller" message and then ViewController lifecycle issues that result in "Unbalanced calls to begin/end appearance transactions" messages, I got the following code working. Based on this experience, I really think Apple should have left a working thing alone in Xcode7/iOS9 update.
//*********** VC1.swift. A translation of working code
class VC1:UIViewController{
private var viewController2:VC2?
private var showVC2: Bool = false
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if(showVC2) {
showVC2 = false
self.pushVC2()
}
}//viewWillAppear
private var info:String? // info from incoming user action.
#IBAction unwindToVC1FromUserAction(incomingSegue: UIStoryboardSegue?) {
// Do app-specific stuff to get info from incomingSegue and
// store in self.info variables.
let myboard: UIStoryBoard = self.storyboard!;
self.viewController2 = myboard.instantiateViewControllerWithIdentifier(
"VC2 Storyboard ID") as! VC2
self.prepareVC2() // Pass info to VC2.info, stuff you would have done in prepareForSegue
showVC2= true
} //unwind
private func prepareVC2() {
self.viewController2.info = self.info // etc..
}
private func pushVC2() {
self.navigationController!.pushViewController(viewController2!, animated:false)
}
} //class
I had this, but it was none of the above. My segue call happened to be inside a block. When I moved the call to the main thread I saw that I had a 'NSUnknownKeyException' error in the new View Controller. Being inside the block seemed to prevent the error from registering in Xcode, so the app just appeared to hang without any errors.
Once that was resolved the original code worked fine.

Pop animation is not working in first UINavigationController of UITabbarController

I don't know what is wrong with my code. i have developed app successfully and all the things working fine except when i launch app first time, In side first navigation controller, the pop animation is not working fine. it seems that Pop without animation. and its working fine when i changed the tab and come back on first tab. and doing push-pop then its working fine.
I tried to figure out problem since week. but could't get success because of lengthy code. I have tried the same animation with creating Tabbar Demo and its working fine.
My app has following hierarchy.
UINavigationController --> UIViewController --> UITabbarController --> Four UINavigationController --> UIViewControlle.
I have taken UITabbarController in my storyboard.
I know that i asked the question and also provide solution for same. I have asked this question long time ago and i am not getting any solution for this because there is illogical bugs. Not every Tabbar base application have same. Here i am adding solution that is result of long time debugging and i found that even single line can break your project.
Actually i have added UITabbarController from storyboard and programmatically created UITabbarController class and type cast it with UITabbarController inside storyboard.
Here my problem is, i forgot to write [super viewDidAppear:animated]; inside -(void)viewDidAppear:(BOOL)animated method. so i will break pop animation first time then it will work fine.
After getting this solution, even i don't know how this line affect whole code. but i don't want the other people to waste their time to find out such single line (unexpected issue) problem. so here i am adding this code.
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}
For Swift 5
Depending on #Jatin Patel - JP answer
Create custom class for your TabBarController
Add this Code in your UITabBarController file
class MyTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}

Resources