I have a application with UIViewController "hierarchy" of this form:
Tab Bar Controller
- View Controller 1
- View Controller 2
- View Controller 3
* View Controller 4
I am using the XCTest Framework to write test methods for my iOS application. View controller 3 is a UITableViewController. When the user selects a row in the table, view controller 4 is shown.
I make a call to the application's window to get the root view controller, the tab bar controller for the application:
// get reference to the tab bar controller
let tabBarController = UIApplication.sharedApplication().delegate!.window!!.rootViewController! as! UITabBarController
But that only gets me access to the three view controllers corresponding to each tab. I checked the number of child view controllers for the root view controller and the number is 3. Makes sense. I checked the number of child view controllers for the 3rd view controller...zero. The view controllers are all setup via IB. I still need to somehow get access to the 4th view controller for my test. Is there a programmatic way to reach the 4th view controller?
A good night's grinding got me to the answer:
In my test code, I was making a call on the UITableView using this:
selectRowAtIndexPath:animated:scrollPosition:
But that method call does not trigger the UITableViewSelectionDidChangeNotification notification to get posted. Since my application's code does use the UITableView delegate function that depends on that notification's posting, I instead just did this:
// get reference to the table view
let tableView = tableViewController.view.viewWithTag(300)! as! UITableView
tableView.delegate!.tableView!(tableView, didSelectRowAtIndexPath: indexPath)
Doing the row selection this way triggered my table view's delegate method to be called and thus the
performSegueWithIdentifier:sender:
inside of that method was called.
The view controller responsible for displaying the site details was loaded and I was able to get a reference to it using the presenting table view controller's method:
let detailViewController = tableViewController.presentedViewController!
This seems to work and I am satisfied thus far...
Related
I am having a multiple UIViewController embedded in a UITabbarController.
These are connected by Relationship Segues.
The starting point, VC1 initially loads data and is then processed to a "detail" view.
Whenever I change tabs and go back to VC1, the application gets stuck, as viewDidLoad is not called.
Is there a way to trigger a function each time VC1 is segued to?
the application gets stuck, as viewDidLoad is not called
The application is not stuck. It is working perfectly. viewDidLoad is called when a view controller is created and loads its view. That only happens once in the life of the view controller. When you leave a view controller and come back to it, it is still there (i.e. it is not being created from scratch), so naturally viewDidLoad is not called.
If your goal is to hear about the fact that the tab bar controller is switching to VC1, give the tab bar controller a delegate and implement tabBarController(_:didSelect:) or similar.
Even better, configure things so that there is no need to do this. If there is common data that is accessed by both view controllers, architect things so that a view controller sends new data up to a data controller and the data controller broadcasts news of the change down to all view controllers that need to know this.
I have a view controller that is a child view controller of my window's root view controller. That child view controller has a table view and when i select a row it tells the parent view controller to present a view controller modally. The modal view controller, however, never appears. I created a bare bones test view controller that just prints viewDidLoad and viewWillAppear. What I notice is that when I call parentVC.present(testVC, animated:true, completion:nil), viewDidLoad is run, but viewWillAppear is not. viewWillAppear is only then called when I interact with the UI in some way. Whether tapping, panning, scrolling or whatever.
I've spent hours trying to debug this. It doesn't seem like the main queue is blocked and I've reduced the problem to its bare bones. The modally presented view controller's viewWillAppear is simply not called until I interact with the UI again.
What could be causing this symptom?
In comments, you mention that you're instantiating your view controller with
let vc = TestVC()
where TestVC is presumably a (largely empty) UIViewController subclass.
A view controller needs a view created either via either storyboard scene (using instantiateViewController), a NIB or, in very rare cases, a view you create in loadView (which you shouldn’t be confused with viewDidLoad).
I’d suggest creating a storyboard scene (assuming you are using storyboards), give it a storyboard ID, and then use instantiateViewController:
let vc = storyboard.instantiateViewController(withIdentifier: "foo")
But just having a UIViewController subclass called TestVC and instantiating it with TestVC() won’t work.
In our discussion, you said you wanted to do this programmatically with no NIB nor storyboard. If so, use loadView. See https://stackoverflow.com/a/37964249/1271826 for an example.
I have a UIContainerView inside of a ViewController which will be presented as a popoverViewController.
There is a UINavigationViewController embedded inside the containerView.
there is tableViewController embedded in the navigationView which performs a segue on cell selection.
like so
when a user clicks on My sessions from the Settings table view controller a delegate method on the (Main profile View Controller)get called to update the preferredContentSize of the popoverViewController.
and when the custom backButton (<) on the UITableviewcontroller the popoverView will change size again. i managed to get it all to work via delegation
however with that being said it only works once... the delegate method from the settings table view controller doesn't get called anymore.
i think after the setting view controller performs a segue on its own the delegate to the main profile view controller is lost and doesn't get called again.
this is how it looks in run time
now the size changes on click of my sessions and returns to original size after user taps on backbutton
but afterwards the delegate method doesn't get called and the view doesn't change size like so
i am using SWIFT 2.0 and Xcode 7.01 any solution on how to retain the delegate method would be really appreciated.
Ok so i solved it by not using the delegates method at all.
When the view controller that is supposed to change the screen size is presented i use
func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
presentingViewController?.preferedContentSize.width = 500
}
and i reverse it in viewWillDisappear
i hope it helps
I'm trying to figure out something about the view controller lifecycle, i understand that viewdidload gets called only once.
BUT, I have a situation were i have 2 view controllers, one is the main view controller and another table view controller.
In the main view controller i have 2 buttons, one for the table view and one to some other view.
The main vorw conrtoller viewdidload does happends once but, Whenever i modal to those other view controllers viewdidload gets call each time.
Im using [self presentviewcontroller: self.navigationcpntroller animated:yes completion: nil]
To modal to the other view controllers from my main view controller. And im using nibs.
What am i not understanding here :/
Tnx
viewDidLoad is called for a view controller the first time the view controller's view has been loaded in the view controller's lifecycle.
If you create a new instance of a view controller each time it is presented then you will see viewDidLoad being called once each time it is presented.
If you create a view controller instance and reuse that same instance over and over, then viewDidLoad is only called once (the first time it is presented).
Since it is normal to create new view controller instances each time you need it, viewDidLoad will be called each time you present it.
I have a tableview that is within a container view. When the user selects any of the rows, a method is called in the parent controller, which tells the parent controller to perform a segue. However, I am unable to figure out why it doesn't work. The code gets called from the didSelectRow -function in the tableView. The method does perform, but it gives me an error about no segue with that identifier.
However, when I call the method(listJobsOfSite) from within the parent view controller it works.
(tableview)
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.jobVC listJobsOfSite:#"locPwn"];
}
parent view controller
-(void)listJobsOfSite:(NSString *)site
{
[self performSegueWithIdentifier:#"JobSegue2" sender:nil];
}
EDIT:
The segue is between view controller 1, and view controller 2. view controller 1 holds a container view, which again holds a table view controller. This tableview controller should tell view controller 1 to segue into view controller 2.
EDIT 2:
screenshot http://tinypic.com/r/30x7dr9/8
You don't call classes. The word you are looking for is "method." You call your listJobsOfSite method that is in your parent view controller class .
Have you made sure you have given the segue an identifier? In your Storyboard you should click on the segue, inspect it, and enter "JobSegue2" in the field marked "Identifier."
If you have done step 2, do you need a container view? What are you trying to accomplish with the Container View + TableView? It sounds like your design would make more sense without the container view and the TableView as a property of View Controller 1.
If your heart is set on using the container view, in your Storyboard try to Control + Drag from your TableView cell to your View Controller 2. Name that segue "JobSegue2." Then you don't need to call any methods in your didSelectRow method. You also don't need a storyboard segue from View Controller 1 to 2. It seems like this question has the behavior you want (the question, not the answer! He is having the opposite problem you are).
Edit: Just noticed you have a Navigation Controller within your container view, so my suggestion above will likely push View Controller 2 within the container view. I'm totally confused by what you're trying to do.