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)
}
}
Related
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.
I have been working on an app for some time and just realized the swiping back in the detail view only returns me to the master view the first time. It also isn't smooth, even when it works on the first time. Instead of smoothly going to the master view, it jumps all at once, even when I swipe slowly. It used to work correctly, but I haven't been testing for this specifically, so I don't know when it stopped working and what I changed to cause this.
A little about how my app is setup...
I have a split view controller that is connected to my MasterTableViewController and DetailViewController.
Both of those are have TableViews and are embedded in Navigation Controllers.
I have set it up so that the app originally loads to the MasterTableViewController instead of going immediately to the DetailViewController, but even when I take this out, the interactive pop gesture doesn't work.
I don't believe I've messed with any of the back button controls. I have looked through my code and storyboard and can't find anywhere that I have. This is part of what is most confusing because these questions (1, 2, and 3) all seem to have problems stemming from changing the back button or can be fixed by entering the following line of code:
self.navigationController.interactivePopGestureRecognizer.delegate = nil
Adding that to my code seems to have no impact on how it behaves.
Here is a picture of how it is setup for reference:
I can usually figure out these things on my own, but this problem baffles me because it works the first time, but not any others. As far as I can tell, nothing changes between the first time and the others. I don't know if anybody else has had the same issue, but any help on why this might be happening would be greatly appreciated. I can provide code or answers to questions on how I am doing certain things if needed. I haven't put any in because there are so many different things controlling this piece that I don't know where to start.
When are you calling self.navigationController.interactivePopGestureRecognizer.delegate = nil?
Doing this will definitely disable interactive pop. It sounds like you may be calling this after a certain UIViewController appears.
What other modifications to UINavigationController are you making? Are you using appearance delegate?
Are you subclassing? If so, are you calling super in all of your method overrides?
Also check your overrides of viewWillAppear in child ViewControllers. This method gets called during an interactive pop. If you are doing a lot of computation (or synchronous calls) on the main thread within this method, it could cause frame drop, hence the choppy animation.
Hope this helps
From Alex Chase's answer : Also check your overrides of viewWillAppear in child ViewControllers. This method gets called during an interactive pop.
added it to viewWillAppear and it worked:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.interactivePopGestureRecognizer?.delegate = self
}
I've been trying to get my project up and running using the SWRevealController classes. I am nearly done writing the basic code for my App so there is already quite a bit of code inside this project. I have tried this inside another project before and it did work.
What I am doing:
I have two ViewControllers. One of them being a SWRevealViewController holding absolutely nothing and one BasicViewController who is just holding a button. I added a Button to the ViewController as well as a IBOutlet. In the ViewDidLoad() Method I added a target to the Button to be fired when pressed:
Inside BasicVC:
class BasicViewController: UIViewController {
#IBOutlet weak var menuButton:UIButton!
override func viewDidLoad() {
super.viewDidLoad()
menuButton.addTarget(self.revealViewController(), action: #selector(SWRevealViewController.revealToggle(_:)), for: .touchUpInside)
}
}
In the Storyboard:
I created a segue from the SWRevealViewController to the BasicViewController. (reveal view controller set controller)
Outcome:
The code compiles perfectly, but results in the button being pressed without anything actually happening. However, if I create a new project and do exactly the same thing, the SWRevealViewController appears.
Q: Is there anything I could do in order to get the solution for this problem? Apparently there's something interfering with the SWReavealViewController class, because it is perfectly working in the other projects.. I am just too "blind" / new to Swift to actually find it.
What I already tried:
Was that I set a breakpoint for when the button is being pressed aka the view being loaded. What I noticed was, that in the test project without any other code, the debugger actually went inside the SWRevealController class, but in my project with a whole lot of other code, it actually does not.
EDIT: It actually does go into the class.
Thanks for reading until here! I'd really appreciate any help. Maybe I am just too "noobie" to find the issue and it actually is just a tiny little issue..
Kind regards.
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.
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.