View did appear not called when view controller (SideMenu) - ios

I have been implementing SideMenu in my iOS app (mailbox). The SideMenu is used to choose the current folder. I created a SideMenu navigation controller and attached a UITableViewController as the root vc.
It works perfectly fine, up until the point where I click on one of the cells, which dismisses the side menu and should load the mail in the original view controller. However, the original view controller's viewDidAppear method is not called. When I tried to call the load function directly, Xcode said that my tableView was nil (it wasn't when it first loaded).
Here is my code for didSelectRowAtIndexPath in the SideMenu table:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
currentFolder = folders[indexPath.row].path
tableView.deselectRow(at: indexPath, animated: true)
self.dismiss(animated: true) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "mail") as! MailViewController
vc.loadMail()
}
}
Here is the loadMail function in the original vc:
func loadMail(showsSpinner: Bool = true) {
...
if let messages = fetchedMessages as? [MCOIMAPMessage] {
self.mailsInFolder = messages
SwiftSpinner.hide()
self.refresher.endRefreshing()
self.table.reloadData()
}
}
Also, here is viewDidAppear in the original vc:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear")
let from = self.navigationController?.transitionCoordinator?.viewController(forKey: .from)
if from is MessageViewController {
print("from is message controller")//should not load
return
}
self.loadMail()
}
Here, viewDidAppear is not called, and the mail doesn't load. What can I do to fix this? Thanks!

I had been working with SideMenu for a while, and I suggest you to use as mainViewController a UINavigationController and then when select one cell of your tableView in the rightViewController
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
currentFolder = folders[indexPath.row].path
tableView.deselectRow(at: indexPath, animated: true)
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "mail") as! MailViewController
{
mainNavController.setViewControllers([vc], animated: false)
}
homeSlide.slideMenuController()?.closeLeft()
}
I hope this helps you, best regards

Related

How to set UINavigationController in SideMenu Controller using Xib (Not StoryBoards) to push new ViewController when Tableview Row Tapped in Swift 5

I am working with XIB files and make a sideMenu controller programatically using this Library https://github.com/Friend-LGA/LGSideMenuController. I make two function to propagate sideMenu in my project as here `//MARK Configure SideMenu
func moveToHomeController(){
let viewController = self.configureSideMenu(viewController: HomeController())
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
func configureSideMenu(viewController: UIViewController)-> UIViewController {
let contentController = SideMenuController(nibName: "SideMenuController", bundle: nil)
let sidemnuNavigationController = UINavigationController(rootViewController:contentController)
let navigationController = UINavigationController(rootViewController: viewController)
let sideMenuController = LGSideMenuController(rootViewController: navigationController,
leftViewController: sidemnuNavigationController,
rightViewController: nil)
sideMenuController.leftViewWidth = UIScreen.main.bounds.width - 100;
sideMenuController.leftViewPresentationStyle = .slideAbove
sideMenuController.leftViewAnimationDuration = 0.6
sideMenuController.isLeftViewSwipeGestureEnabled = false
sideMenuController.isRightViewSwipeGestureEnabled = false
return sideMenuController
}
I get SideMenu working fine, now my problem is that whenever i click on tableview row(make in sideMenuController) to push to new viewcontroller it show half new viewcontroller above sidemenu same size as sideMenu. How i can get fullscreen viewcontroller with back button using pushViewController.Here is my code for row select
` func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
let viewController = EditProfileViewController(nibName: "EditProfileViewController", bundle: nil)
self.navigationController?.pushViewController(viewController, animated: true)
self.sideMenuController?.hideLeftView()
print("row tapped")
}`
I checked and correct it as i was trying to present another viewcontroller screen over "LGSideMenuController" instead of using push transition.Solved using this piece of code.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
let viewController =HomeController(nibName: "HomeController", bundle: nil)
self.sideMenuController?.hideLeftViewAnimated(sender:self)
self.sideMenuController?.rootViewController?.show(viewController, sender: self)
}

Is it possible to navigate from a tab bar controller to another tab bar controller?

I have an app with three tabs as the root navigation, and there's a table view in the first tab. So when a user clicks on a table cell user should navigate to another View which contains two tabs. How do I achieve this?
Current Storyboard
This is what I have so far. I'm still learning ios development and I want to know if this is possible
Remove the storyboard segue from the table view to the second tab bar controller. And present the second tab bar controller from the table view controller's didSelectRowAt method. And you can pass data to the embedded view controllers like this
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let secondTabBarController = self.storyboard?.instantiateViewController(withIdentifier: "SecondTabBarController") as? SecondTabBarController {
if let navControllers = secondTabBarController.viewControllers as? [UINavigationController] {
if let fourthVC = navControllers.first(where: { $0.topViewController is FourthVC })?.topViewController as? FourthVC {
fourthVC.name = "name"
}
if let fifthVCvc = navControllers.first(where: { $0.topViewController is FifthVC })?.topViewController as? FifthVC {
fifthVCvc.id = 20
}
}
self.present(secondTabBarController, animated: true, completion: nil)
}
}
Replace the class names and storyboard identifiers with proper class names and identifiers
class FourthVC: UIViewController {
var name: String?
override func viewDidLoad() {
super.viewDidLoad()
print(name)
}
}
class FifthVC: UIViewController {
var id: Int?
override func viewDidLoad() {
super.viewDidLoad()
print(id)
}
}
Yes you set any check for that in a single tab controller by this condition which tab you want to show reset from their.
When clicking on the row from the table view, you can use some code like this:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Segue to the other UITabBarController, pass selected information
let selectedCell = tableView.cellForRow(at: indexPath.row)
if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "YourTabBarControllerIdentifier") as? YourTabBarController {
viewController.selectedIndex = 2 // or the index you want by default
viewController.modalTransitionStyle = .crossDissolve // or transition you want
self.present(viewController, animated: true, completion: nil)
}
}

TableView DidSelectRowAt() latency

Hello I actually use a tableview in my app. I have this lines of code which switch from a VC to a mother and it work fine everywhere :
let vue = MAINSTORYBOARD.instantiateViewController(withIdentifier: "accueil") as! Accueil
self.present(vue, animated: true, completion: nil)
In my tableView I use the function DidSelectRowAt ( this execute when I click on a row/cell) to do this (switch of VC)
But you've already understood when I click it work but with latency.
This latency can is sometimes 1-2s sometimes up to 12s it's random. That's weird.
I specify the function above work instantly with buttons and others.
this is the code (I write only important things) :
class Horaire: ViewController, UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vue = MAINSTORYBOARD.instantiateViewController(withIdentifier: "accueil") as! Accueil
self.present(vue, animated: true, completion: nil)
}
and the other class :
class Accueil: ViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad executed")
}
}
So when I click on a cell of my tableview it immediately print "viewDidLoad executed" but VC switch is done only after some random seconds.
Why does I have this latency and how to fix it ? it don't use segue
The first thing that came to my mind was to put the block in the main queue. I know didSelectRowAt is supposed to run in the UI thread, but I saw on the internet a couple complaints about this very same thing. Looks like a bug to me.
class Horaire: ViewController, UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
DispatchQueue.main.async{
let vue = MAINSTORYBOARD.instantiateViewController(withIdentifier: "accueil") as! Accueil
self.present(vue, animated: true, completion: nil)
}
}
}
You can see for some odd reason this seemed to work for these people:
https://github.com/HeroTransitions/Hero/issues/79

How to return to initial ViewController without attaching Nav Bar

I am using the Facebook API and I am trying to implement the logout feature. When a UITableViewCell is tapped, I want to return to the original login page. I tried just creating a normal segue from the VC to ViewController.swift(i.e. initial login page), but it attaches the navigationBar, which isn't what I want.
I've tried several things. This is my current code
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 5 {
NSUserDefaults.standardUserDefaults().setObject(nil, forKey: KEY_UID)
NSUserDefaults.standardUserDefaults().setObject(nil, forKey: SELECTED_SPORTS)
let loginViewController: UIViewController = ViewController()
self.navigationController?.popToRootViewControllerAnimated(true)
}
}
this just pops me back to the previous VC, which isn't what I want. I tried doing Unwind Segues, but I'm not allowed to drag onto the Exit button of the Storyboard, which is also confusing.
If you don't want navigationBar then just hide it.
self.navigationController?.setNavigationBarHidden(false, animated: true)
This may help you brother do it this way.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
if indexPath.row == 5
{
NSUserDefaults.standardUserDefaults().setObject(nil, forKey: KEY_UID)
NSUserDefaults.standardUserDefaults().setObject(nil, forKey: SELECTED_SPORTS)
let LoginVCOBJ = UIStoryboard(name: "MainStoryboard", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("loginViewControllerblVC_OBJ") as! loginViewController
self.navigationController?.viewControllers = [LoginVCOBJ]
}
}

how to programmatically deselect a static cell iOS

I have a static cell and when clicked it launches a modal view. Except when i return from the modal view the cell is still selected? Why is it doing this and how can I make it only make the cell selected until the modal completely covers the view.
Thanks in advance
For Swift 2 :
override func viewWillAppear(animated: Bool) {
if let indexPath = self.tableView.indexPathForSelectedRow {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
For Swift 3 and 4 :
override func viewWillAppear(animated: Bool) {
if let indexPath = self.tableView.indexPathForSelectedRow {
tableView.deselectRow(at: indexPath, animated: true)
}
}
If you use a UITableViewController instead of a UIViewController this will be done automatically. Otherwise, you need to do the deselecting yourself using
deselectRowAtIndexPath:animated: on the UITableView. The best place to do this is probably on viewDidAppear: of the presenting view controller. That way, the user still sees the deselecting animation allowing them to reorient themselves.
If you don't need to track the selected row for other purposes, you can use
indexPathForSelectedRow to determine which index path needs to be deselected (if any).
I know this is too late but may help someone who's using Swift -
This will give a nice effect when you return to masterViewController from detailViewController
override func viewWillAppear(animated: Bool)
{
if let indexPath = self.tableView.indexPathForSelectedRow
{
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
Otherwise add this delegate method of TableView and call it from didSelectRowAtIndexPath
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
if let indexPath = tableView.indexPathForSelectedRow
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
You can use this in your UITableViewController;
- (void)viewWillAppear:(BOOL)animated
{
[yourTableView deselectRowAtIndexPath:[yourTableView indexPathForSelectedRow] animated:YES];
}
In your condition, yourTableView property should be self.tableView
swift 3
override func viewWillAppear(animated: Bool) {
tableView.deselectRow(at: tableView.indexPathForSelectedRow!, animated: true)
}

Resources