viewDidAppear not being called after pushViewController - cocoa-touch

I am writing an app that pulls information from a database, displays in a table, and allows the user to get details by selecting an item from the table. Whenever the table updates, the values in the list are correct, but the table displays the old information (i.e. if the table originally had 3 items and now has 2, the table will display the original 3 items, but break if the user tries to tap the 3rd item). The same issue occurs with my details view. If the user selects one value, the view changes for that information. If they navigate back and select a new value, the view changes but displays the information from the first selection. I've attributed both of these to the views not calling viewDidAppear when they appear. I am using a Navigation Controller to load the views, but they still aren't calling the method.
This is how I show my listView : UITableViewController
-(IBAction)viewInventoryClicked:(id)sender {
[DBHelper getAllBottles:[appDelegate getDBPath]];
if(self.viewList == nil) {
//instantiate view
}
[appDelegate.navigationController viewWillDisappear:YES];
[appDelegate.navigationController pushViewController.self.viewList animated:YES];
}
My detailsView (UIViewController) is shown in a similar fashion. The navigation controller resides in the AppDelegate. The main window is loaded with:
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
The mainWindow and my ModalView are both successfully calling the viewDidAppear methods. I am completely stumped on why these other two are not calling them. Thanks in advance for the help.

I figured it out. The issue wasn't in the way I was changing view, but in the way my interfaces were set up. I had all of my viewControllers in my MainWindow.xib, instead of the in the *.xib of the view previous.

Related

Avoid using prepareForSegue in Objective-c?

In my initial view controller, I have the following code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showSearch"]) {
[segue.destinationViewController setInitialLocation:self.locationManager.location];
}
}
When a button is pressed in the initial vc, the segue labeled "showSearch" is activated and the second view controller is loaded with the data inside. The second view controller is a map, and the data are pins at certain locations, collected from the Parse database. My question is, is there anyway to avoid the initial view controller? In other words, I don't want to load up my app, then have to press a button to get to the map view. I want the map view to load first, with the pins already on the map.
You can change your initial view controller by going to storyboard, selecting the view controller you want to become the new initial view controller, going to the attributes inspector, and checking "is initial view controller."
In first view controller's viewDidLoad call the button method which is responsible for the segue to second view controller.
Solved the problem by adding this to the viewDidLoad.
[self performSegueWithIdentifier:#"showSearch" sender:self];
Not ideal, but it works. Although it works fine on my phone, it doesn't seem to work perfectly on the xcode simulator.
If you have a lot of database related code in an initial VC, but that VC isn't handling an UI, maybe you could change your program so that the database code was separated out into its own class. Then the map VC can be your initial VC and it can call your database class to get the data.
So, maybe you have a location manager class with a getInitialLocations method that the map VC can call to load itself with data. Just guessing based on your description.

Showing Toolbar on 2nd ViewController

I have two view controllers on the same storyboard. What I want to do is send an array of string values to the table view control on another view controller.
ViewController2 *second=[self.storyboard instantiateViewControllerWithIdentifier:#"View2"];
second.arrayFromVC1=areaArray;
[self presentViewController:second animated:YES completion:nil];
The second view controller has a toolbar control at the top by default. (See below.)
Passing data to another view controller wasn't easy for me, who has been using Xcode for two weeks. I somehow managed it. So an array of strings is sent to the 2nd view controller through an array variable (arrayFromVC1) set on the 2nd implementation file. I suppose experienced Xcode users know what I'm talking about. Anyway, the 2nd view controller does receive a list of values as shown below.
Well, the problems are that the toolbar control on the 2nd view controller will disappear when the user gets to see the list and that the table view control (UITableView) occupies the entire window. I understand that you can control the size of the table view control by specifying values under the viewDidAppear method. But my question is... Is that how things work with iOS and Xcode? So if I want to display that toolbar control at the top, I have to do it programmatically by writing code under the viewDidAppear method as well?
Thank you for your advice.
Tom
Tom, are you using interface builder and storyboards? If so, select the ViewController in IB, go to Editor (in the top menu) --> Embed In --> Navigation Controller.
This will embed the chosen VC and any VC it segues to (and so on) into a Nav Controller.

presenting view controllers using ios5 and storyboard

Does using [self presentModalViewController:videoViewController animated:YES]; stack up multiple views?
On videoViewController I'm loading in several UIWebViews and each one of them loads in a video. And I have a button on that view which allows the changing of categories. When the category button is clicked, it shows a popover view and inside that view are several buttons for different categories. When one of them buttons are pressed, I'm doing the following to get back to videoViewController:
VideoViewController *videoViewController= [self.storyboard instantiateViewControllerWithIdentifier:#"VideoVC"];
[self presentModalViewController:videoViewController animated:YES];
Which works, it dismisses the category popover view and goes back to videoViewController loading in different videos. But then, changing the category a few times my app is starting to crash after getting 'did receive memory warning' messages.
I have a category 'all' which loads in all the videos and don't get no such message, but then changing the category several times (each category of course loads in less videos as it's being filter) I'm getting warnings.
So my real question really is, when I'm changing category and calling [self presentModalViewController:videoViewController animated:YES]; is it just racking up a view every time I change category? So for instance if I change category 5 times, will I have 5 videoViewController views just sat on top of each other? If so, what's the best way about going to avoid this?
I tried [self presentModalViewController:videoViewController animated:YES]; instead to see if that would make a difference, but the viewViewController doesn't reload and the category popover view doesn't dismiss.
This is for an iPad app if that makes a difference.
Thanks.
Every time you use this line:
VideoViewController *videoViewController= [self.storyboard instantiateViewControllerWithIdentifier:#"VideoVC"];
You are creating a new instant of VideoViewController and all that UIWebviews. What you need is using Objective-C's delegate pattern. When user selected one of the buttons in the popover view, you need to make a callback to the original instant of VideoViewController and passing back which button (some type of number, for example) that user has selected and handling the changes from there.

Increasing number of living Views

I've set up a really simple project using storyboards including two views as shown here: http://i.stack.imgur.com/iRx21.png. The navigation can be done by either selecting a cell in the custom table view or hitting the back button labelled with "<<". Everything works fine except the following:
when I switch between the views, every time an instantiation happens. The profiling shows an increasing number of view objects. I would like to keep only one of each view and instantiation should be happen only once. What am I doing wrong? (I'm using ARC.)
Thanks in advance!
You should not link your back button to the parent view controller. This is what causes the new instantiation.
The way to go is to embed the table view into UINavigationController (in IB, choose Editor -> Imbed In -> Navigation Controller. Then change your segue to a Push segue. You can of course hide the navigation bar etc. to make things look exactly as you like. Then, link the back button to the controller with an IBAction and in the handler do a simple
[self.navigationController popViewControllerAnimated:YES];
This would be the appropriate logic of what you are doing. Of course, you can also push the web view modally and then handle the button click with
[self dismissModalViewControllerAnimated:YES];

How do I create a UINavigationController with a default "back" state?

I have a UINavigationController, complete with table view and associated magic.
The data I'm populating that table view from may have items from multiple categories, but the default view for the user will be one in which they are viewing all of the items, and then they have the ability to move backwards to a different table view that would allow them to select a different category, which would then return to the original table view with the appropriate data populated.
What's the proper approach for this? I can't seem to wrap my head around how I would make the navigation controller give me a back button (with appropriately wired up actions) without having come from a previous view in the stack (which wouldn't really exist at launch time if I start the user off from what is essentially the detail view, in stack terms.)
Also, the back button should be titled "Groups", not "Back", but that's really just an implementation detail. :)
Update: This issue finally manifested itself in production code, and here’s how I fixed it:
My UINavigationController is created in a nib, with the root view set as the “groups” view. Then, in my app delegate, I push the second view onto the stack while the app is launching.
That works fine for achieving the proper stack, but that doesn’t help with the back button title, because the navigation controller didn’t seem to want to grab the title from the root view, and instead was showing a back button with “Item” as the title.
So, on the pushed view, in viewDidLoad, I set:
self.navigationController.navigationBar.backItem.title = #"Groups";
and that did the trick.
The only potential downside of doing it this way would be if the pushed view controller were ever used in a scenario where the view below it wasn’t the groups view, but since the design of this particular application ensures that never happens, I’m accepting that failure. ;)
Another update:
I’m an idiot. Just set the title property of the navigationItem provided by the navigationController in Interface Builder, and boom, no issue. Or do it in code. It doesn’t matter, just don’t do it by setting the backItem.title way I show you above. That’s just dumb.
In your application delegate's .m file in the application:didFinishLaunchingWithOptions: method just push your view controllers like you normally would with[self.navigationController pushViewController:your_view_controller animated:YES]; and it should push them on before the application's first view controller appears.
To change the text of the button to Groups just call this before pushing your controllers.:
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle: #"Groups" style: UIBarButtonItemStyleBordered target: nil action: nil];
[[self navigationItem] setBackBarButtonItem: newBackButton];
[newBackButton release];