NavigationController nested in TabController animation bug - swift

I try my best to explain what is happening.
I have updated the XCode to Version 10.1 (10B61)
And the iOS on my iPhone and Simulator is v12.1
My app has a TabController with 5 tabs.
First: Posts
Fifth: Profile Posts
These are embedded into a navigation controller (In case someone
clicks on the comments button)
So. I've noticed that if I run my app and I click the comments, it pushes that vc in a weird way to the screen, then clicking back just "bumps" back. Also slide back isn't working.
However, if I switch tabs first then everything works fine.
VIDEO:
https://www.youtube.com/watch?v=fgS3j21L8Js
As you see in the video everything is fine after switching to Profile Posts + back .
UPDATE 1:
So if I start my app, switch to another Tab, then back to the original, it works fine.
Requested code:
func commentsButtonTapped(sender: UIButton) {
let touchPoint:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
openDetails(indexPath: indexPath, shouldShowKeyboard: false)
}
}
func openDetails(indexPath: IndexPath, shouldShowKeyboard : Bool) {
if (self.tableView.cellForRow(at: indexPath) as? WorldMessageCell) != nil {
let storyboard = UIStoryboard(name: "Additional", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "DetailsViewController") as! DetailsViewController
vc.postId = PostIds.shared.nearby.ids[safe: indexPath.row]
vc.shouldShowKeyboard = shouldShowKeyboard
self.navigationController?.pushViewController(vc, animated: true)
}
}
UPDATE 2:
Solved the problem by forcing the TabController to switch between tabs..
override func viewDidAppear(_ animated: Bool) {
self.selectedIndex = 1
self.selectedIndex = 0
}
But that's not how it should work..
UPDATE 3:
I have tested it, if I make the navigation controller->vc the initial vc (so no tab controller) everything works fine.
But as soon as the navigationcontroller is nested inside the tab, it happens.
I made a new project to test if this is a version specific bug but no, everything works fine there. So the issue must be with my app.
What could generate issue like that (in the video)?

Ohh.. I have found the problem & bug:
So if you have navigation controllers nested into a tab controller that calls it's viewDidLoad() function, then the navigation controller will have problems.
The code I had to remove totally:
override func viewDidAppear(_ animated: Bool) {
// here i had some code ... /
}
Now everything works..

Related

Going from one storyboard to another from a tableView in Swift 5 / Cocoa

have search on that topic without finding a solution that work.
I am building a accounting application with several storyboard. Main, Customer( clients), invoice (factures)... etc. I can go from the main storyboard to the customer of Invoice storyboard by click a button no problem... The button (main SB) is linked to the Customer or Invoice storyboard reference.
In the clients storyboard, I have a tableView with that list the purchased historic of that customer. I would like to to be able to double clic on a specific invoice, and open that invoice in the Invoice storyboard.
The double clic part work fine, print message work... but the program crash after with the message: Could not cast value of type '__NSCFBoolean' (0x7fffaab000c8) to '__C.NSViewControllerPresentationAnimator'
That code was taken andadapted from another post. I have tried different variation withou success ie same error message.
I have not work on the part where I transfer the Invoice number from the client SB to the Invoice SB. I will likely transfer the Invoice number with a segue and have the Invoices program look if that variable if not nil, after loading
Invoice storyboard filename : factures.storyboard
facture ViewController Class : FacturesVC
ViewController storyboardID : facturesVC_id
#objc func tableViewDoubleClick(_ sender:AnyObject) {
if tableView.selectedRow >= 0 {
print ("VC545:", tableView.selectedRow)
//let storyboard = NSStoryboard(name: "factures", bundle: nil)
//let VC = storyboard.instantiateViewController(withIdentifier: "facturesVC_id") // give same error
let VC = NSStoryboard(name: "factures", bundle: nil).instantiateController(withIdentifier: "facturesVC_id") as! FacturesVC
self.present(VC as NSViewController, animator: true as! NSViewControllerPresentationAnimator)
}
}
Your code does not make sense.
It looks like you are trying to call present(_:animator:). If you call that, you need to pass it an animator (an object of type NSViewControllerPresentationAnimator.)
Your code does not create a NSViewControllerPresentationAnimator.
Here is an outline of how you need to change it:
let vc = NSStoryboard(name: "factures", bundle: nil).instantiateController(withIdentifier: "facturesVC_id") as! FacturesVC
let animator = // Code to create an NSViewControllerPresentationAnimator
self.present(vc, animator: animator)
I haven't worked with NSViewControllerPresentationAnimators before. (I mostly work with iOS these days.) You should probably search for tutorials on NSViewControllerPresentationAnimator if you are unsure how to proceed.
Finally, I have found the answer I was looking for...
Here is the code.
#objc func tableViewDoubleClick(_ sender:AnyObject) {
if tableView.selectedRow >= 0 {
let srow = tableView.selectedRow
//print ("VC551:", srow)
fact_nb = Int(fact_tbv[srow].id_f) ?? 0 // invoice nb that you want to segue
let storyboard = NSStoryboard(name: "factures", bundle: nil)
let VC = storyboard.instantiateController(withIdentifier: "facturesVC_id")
//self.presentAsSheet(VC as! NSViewController) work fine for sheet
// self.presentingViewController // data are laoded but nothing show up
// self.presentAsModalWindow(VC as! NSViewController) // OK for modal, cannot be resize , yellow button missing on bar
// self.present(VC as! NSViewController, animator: false as! NSViewControllerPresentationAnimator) // true or false... need a animator
let window = NSWindow(contentViewController: VC as! NSViewController)
window.center()
let windowController = NSWindowController(window: window)
windowController.showWindow(nil)
//see How to Perform Segue https://www.youtube.com/watch?v=JL0xuZ4TXrM
self.performSegue(withIdentifier: "gotofact", sender: nil) // segue identifier name : gotofact
}
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
let sb = segue.destinationController as! FacturesVC
print ("VC569:", fact_nb)
sb.factnb = fact_nb
}

The screen comes out from behind

I don't know why this is happening, already I have a similar functions on the project and this isn't happening.
When I delete the account and I to the previous screen or if the user is on background and open it again the 2 methods below cause you to be sent to the main screen but I detected this problem (in the picture)
There is the function when I go to the home when I delete the account
private func goToHomeWithLogin(){
let home = HomeAssembly.presenterView()
Utils.getTopViewController()?.present(home, animated: true)
And the getTopViewController do this:
func getTopViewController() -> UIViewController? {
if let viewController = UIApplication.shared.keyWindow?.rootViewController {
if let modal = UIApplication.shared.keyWindow?.rootViewController?.presentedViewController {
return modal
} else if let navigationController = viewController as? UINavigationController {
return navigationController
}
}
return nil
}
When I drag down the screen comes out from behind
looks like default card style of UIViewController.present(...) if you want it full screen (without the swipe down feature) try home.modalPresentationStyle = .fullScreen before presenting it
let home = HomeAssembly.presenterView()
home.modalPresentationStyle = .fullScreen
Utils.getTopViewController()?.present(home, animated: true)

How to remove duplicate VC in swift?

I am making a game, where I go from the main screen to a ArcadeViewController, which loads up the SKScene, and save the previous VC as prevVC.
I use segues created in storyboard to move between VC.
The problem is that each time I move to a VC, instead of moving into the old one, a copy gets created, and both of them start to run at the same time.
I tried removing them by running the following codes, when I move into the VC:
override func viewDidAppear(_ animated: Bool) {
UIApplication.shared.keyWindow?.rootViewController = self
self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)
prevVC.reloadViewFromnib()
prevVC.dismiss(animated: false, completion: nil)
UserDefaults.standard.set(0, forKey: "since_The_Last_Ad")
}
extension UIViewController {
func reloadViewFromnib() {
let parent = view.superview
view.removeFromSuperview()
view = nil
parent?.addSubview(view) // This line causes the view to be reloaded
}
}
It helped to reduce the number of copies created, but still the are some.
How can I remove duplicate views?
So the solution ended up being to use the normal segue to launch the ArcadeVC from GameVC(start VC) for the first time.
Then set the ArcadeVC as rootVC:
UIApplication.shared.keyWindow?.rootViewController = self
Then use a normal segue to go back to the GameVC.
After the ArcadeVC is set as the rootVC, just use normal segue to the ArcadeVC form GameVC, and unwind from GameVC to AracdeVC.

Application crashing without information about crash when transitioning to another view controller

I have two view controllers, LoginViewController and TermsAndPrivacyViewController.
On first view controller, there is a button that has IBAction, which opens TermsAndPrivacyViewController. On TermsAndPrivacyViewController I have web view, that loads url I am passing from LoginViewController. So, this is the code(Login view controller):
#IBAction func tosAction(_ sender: Any) {
if let vc = UIStoryboard(name: "Login", bundle: nil).instantiateViewController(withIdentifier: kTOSViewControllerIdentifier) as? TermsAndPrivacyViewController{
vc.url = URL(string: kTOSUrl)
self.navigationController?.pushViewController(vc, animated: true)
}
}
On TermsAndPrivacyViewController, I have this:
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
if let `url` = url {
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
}
}
So, when I hit a button, app crashes SIGABRT message, and nothing else. Also, I don't get any crash report on Firebase Crashlytics (I have detached an app from a debugger first, and produced a crash).
Now, the strange part :/ ... If I put a breakpoint on a first line of tosAction() method, and go step by step (or just let it continue), everything works normally. No crash???
Am I missing something obvious here? What is the reason of crashing? Also, I tried to put Exception Breakpoint but nothing changes. I only get this:
and a console:
so, kinda no information about crash at all.
EDIT
Ok, now the even more strange part :) I just tried app on different phones.
App crashes on iPhone 6s+, iOS 12.1(16B5059d), but it works normally on iPhone 6, iOS 12.0 (16A366)
maybe you use library or framework that not supported by those device.
you must see the error
did you try this?
when the app crashing, in the console press cmd+F and search exception.
now you can see your error
hope to helpful.
Maybe you can use segue methods inside your LoginViewController.
#IBAction func tosAction(_ sender: Any) {
performSegue(withIdentifier: "GoToWeb", sender: nil)
}
}
And call prepareForSegue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "GoToWeb") {
let vc = segue.destination as! TermsAndPrivacyViewController
vc.url = "YOUR_URL"
}
And the code inside TermsAndPrivacyViewController don't change
Edit:
Maybe your not binding well your UIButton, can you verify in the right panel, in the section "Show the connection inspector" if your button is call only once.
To get further information on this type of crashes, open the Breakpoints menu (or press CMD+8), click the plus icon in the bottom left corner and press Exception Breakpoint.... Right click, then edit. Add an action of the type Debugger Command and enter the following:
Reproduce the crash again, this time the console will output a more useful error message.

Using UINavigationBarDelegate method shouldPopItem in Swift

I've been trying to figure out how to use the UINavigationBarDelegate method shouldPopItem with a popover in Swift. I've done lots o' digging around and trying this and that, with no success. I'm hopeful someone can point me in the right direction.
I start with a UIViewController that has a number of buttons the user can click. As an example, there is a button that calls back to this method:
#IBAction func manageVerbListsButtonPressed(sender: UIButton) {
vc = ManageListsViewController(nibName: "ManageListsView", bundle: nil)
vc.preferredContentSize = CGSizeMake(600, 600)
vc.modalPresentationStyle = .Popover
let popoverController = vc.popoverPresentationController!
popoverController.sourceView = sender
popoverController.sourceRect = sender.bounds
popoverController.permittedArrowDirections = .Left
popoverController.delegate = self // could you set the popover delegate to the vc, so the vc could control the dismiss?
presentViewController(vc, animated: true, completion: nil)
}
This correctly opens a popover with ManageListsView as the presenting controller. That controller has a view with a table. When the user clicks on a table row, the didSelectRowAtIndexPath method fires:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let vc = EditOneListViewController()
let vl = Lists[indexPath.row] // this is an array of list names
vl.isNew = false
vc.List = vl // give the next controller the list to edit
navigationController?.pushViewController(vc, animated: true)
}
Again, this correctly pushes the EditOneListViewController.
What I want to do, but haven't figured out how, is to use the UINavigationBarDelegate method shouldPopItem to determine whether the navController should pop back to the table view, depending on whether the user has done something on the EditOneListViewController view. That is, if the user has edited something and not saved it, I want to use the shouldPopItem to put up an Alert indicating that and return to the view so the user can save the edits. (The list has an isDirty boolean that I can test for whether it's been saved.) If the user has saved edits, I want the navController to pop back a level.
I have done this in Obj C in earlier iOS's, but I'm darned if I can figure out how to do it with iOS 9 and Swift and presentationControllers. Any help at all will be greatly appreciated.