I have a tableviewcontroller that needs to drill down and show 3 layers of data. I have no problem drilling down but when I go back, the cells and table become empty. I'm currently using storyboard and I didn't have this problem when I was using nib. All I had to to was alloc and initWithNibName the same view and it would create another instance of the same TableView and I can go back and all the data would be there.
I've tried using segue but it's not working as I need the tableviewcontroller to segue back to itself if I'm drilling down. I've created my own method to push the view controller and pass data into the new instance of itself
- (void)drillDown{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
ExerciseTableViewController *tableView = [storyboard instantiateViewControllerWithIdentifier:#"ExerciseTableView"];
tableView.title = _detailTitle;
tableView.delegate = self;
tableView.level = _level;
tableView.currentSMID = _currentSMID;
tableView.currentMID = _currentMID;
tableView.muscleNameArray = _muscleNameArray;
if (_level == 2) {
tableView.submuscleNameArray = _submuscleNameArray;
}
[self.navigationController pushViewController:tableView animated:YES];
}
This is what I have in my viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addExercise:)];
self.navigationItem.rightBarButtonItem = add;
NSLog(#"level: %i, currentSMID: %i, currentMID: %i", _level, _currentSMID, _currentMID);
if (self.managedObjectContext_ == nil) {
self.managedObjectContext_ = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
if (_level == 1) {
_submuscleNameArray = [self submuscleGroup:_currentMID valueForKeyPath:#"submuscleGroup"];
_submuscleIDArray = [self submuscleGroup:_currentMID valueForKeyPath:#"submuscleID"];
} else if (_level == 2) {
//loading and sorting exercise list
_exerciseList = [self loadExercise:_currentMID sub:_currentSMID];
_exerciseListSorted = [self sortKeysByName];
} else {
[self loadMuscleGroup];
}
}
The table view is only populated when I put some of this code in the viewDidAppear but I can't differentiate between drilling down and going back up with the viewDidAppear.
Isn't the navigationController suppose to save my current view and push a new view and when I pop the new view, I go back to my current view?
It seems like everytime I pop the view, the previous view needs to load all over again and this is causing my previous views to become blank.
Any suggestions?
Storyboard attached
So I figured out what was the issue. I have a variable called _level and I use it to track which level of drill down I'm in. When passing this variable to the next level, I've replaced the current level with the next level number therefore when I come back to the previous view. The current level is the same as the next level which screwed things up.
I've solved it by creating a new variable called nextLevel and passing that down instead.
Very basic error on my part.
Related
If a core data check is empty, I want to leave a certain view controller and segue to a different view controller.
The core data check is called from View WIllAppear.
Right now, I have the command to make the transition at the end of the core data pull. If the pull comes back empty ,then I trigger the code to segue to another view controller.
This is causing a problem since the page is not yet loaded when I ask IOS to go to a different page. However, I really don't want to the page to load first.
Also, I don't want to move this code out of viewWillAppear, for example, to viewDidLoad as I want to do a fresh check of the data every time someone visits the screen.
Can anyone suggest right way to do this?
Here is my code:
In viewWillAppear:
[self updateInterface];
In updateInterface:
self.item = [self getLatestItem:userid inManagedObjectContext:_managedObjectContext];
in getLatestItem
NSArray *matches = [_managedObjectContext executeFetchRequest:request error:&error];
if (!matches ||[matches count]<1) {
// handle error
self.noNewItems=1;
[self gotoListChallenges];
} else {
NSLog(#"got at least one match");
item = [matches lastObject];
}
return item;
}
- (void) gotoListItems {
UIStoryboard *storyBoard = self.storyboard;
listItemsVC *listVC =
[storyBoard instantiateViewControllerWithIdentifier:#"listItems"];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: listVC];
[self presentModalViewController:nav animated:YES];
}
I'm trying to populate UITextFields inside a UITableViewController with a click of a cell. So, I created an init method like:
- (id)initWithObjetoFormulario:(ObjetoFormularioGerenciador *)umObjeto
{
self = [super init];
if(self){
self.objetoFormulario = umObjeto;
}
return self;
}
In my ViewDidLoad I put the line if(self.objetoFormulario){ and after that link the UITextFields to my Object. I don't think there's anything wrong at this point.
So, my Second TableViewController is a SearchDisplayController, it finds the Data I need and at didSelectRowAtIndexPath I have:
ObjetoFormularioGerenciador *objeto = [[ObjetoFormularioGerenciador alloc] init];
[objeto RecebeArrayComDadosECriaObjetoFormularioGerenciador:_arrayComDados eEmail: [searchResults objectAtIndex:indexPath.row]];
GerenciarSeriesTableViewController *gerenciador = [[GerenciarSeriesTableViewController alloc] initWithObjetoFormulario:objeto];
[self.navigationController pushViewController:gerenciador animated:NO];
As I don't have the actual objects in my cells, I call a method to retrieve the object according to the cell entry, that is working as well, now, it opens a blank TableView when I click the cell. It should go Back to my tableView with static Cells containing UITextFields and populate them.
When I use this code:
ObjetoFormularioGerenciador *objeto = [[ObjetoFormularioGerenciador alloc] init];
[objeto RecebeArrayComDadosECriaObjetoFormularioGerenciador:_arrayComDados eEmail:[searchResults objectAtIndex:indexPath.row]];
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
GerenciarSeriesTableViewController *gerenciador = [sb instantiateViewControllerWithIdentifier:#"GerenciarSeriesTableViewController"];
[self.navigationController pushViewController:gerenciador animated:NO];
It does open the TableView I want, but it doesn't populate the UITextFields as I didn't pass any object.
Thanks.
Yes, you really don't generally have custom init methods for view controllers, but rather rely upon the standard ones, and then once the view controller has been instantiated, you'd just set the property then, e.g.:
ObjetoFormularioGerenciador *objeto = ... // create and configure objeto
GerenciarSeriesTableViewController *gerenciador = [self.storyboard instantiateViewControllerWithIdentifier:#"GerenciarSeriesTableViewController"];
gerenciador.objetoFormulario = objeto;
[self.navigationController pushViewController:gerenciador animated:NO];
You can also have a segue between the two view controllers, give it an identifier, and then call [self performSegueWithIdentifier:...], and then set the objetoFormulario in the prepareForSegue method. But the above technique should work fine, too.
Is is possible to have a UIView preloaded so that it will load faster when the user taps on button to load it? Currently I've got a library of informaiton that I'm attempting to load when the user taps a button, and for now it seems to be "ok" , but it makes the navigation to the page choppy, because of all the information in the library it's loading.
Thanks in advance!
It should be possible to split the setup of a View Controller from code that displays the view after a button is pushed. This will eliminate the lag when the button but the task to setup the view controller still need to be done sometime during execution (You can for example put it in the ViewdidAppear method so it is executed while waiting for the button to be pushed.
Take this code for example:
-(IBAction) button_pushed {
/*setup */
NewVC *vc = [[NewVC alloc] init];
vc.var1 = var1;
vc.var2 = x;
[vc setup];
/*display */
[self.navigationController pushViewController:vc animated:NO];
return;
}
You can split the code that setup the view from the code that displays the view
into :
#synthesize vc;
…..
- (NewVC) setup {
//setup
NewVC *vc1 = [[NewVC alloc] init];
vc.var1 = var1;
vc.var2 = x;
[vc setup];
return(vc1);
}
-(void) ViewDidAppear {
if (setupready) {
vc = [self setup];}
return;
}
-(IBAction) button_pushed:(ID) sender {
//display
[self.navigationController pushViewController:vc animated:NO];
return;
}
I'm confused. I have a navigation controller with a BarItem which opens a first view. After some work is done, I want this view to disappear and I want a second view to open.
root view: navigation controller
first view: activity indicator, where some data is put together
second view: MFMailComposeViewController
In the root view, the BarItem runs these lines to open the first view:
IndicatorViewController *indicator = [[IndicatorViewController alloc] initWithNibName:#"IndicatorViewController" bundle:nil];
indicator.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:indicator animated:YES];
The first view (IndicatorViewController) does some work and finally runs
[self dismissModalViewControllerAnimated:YES];
This works fine. But - how do I open the second view?
I tried this:
I open the second view. After closing the second view, my first view pops up again (since it is still there) and get's dismissed at this point. This code is placed in the first view:
- (void) viewDidAppear:(BOOL)animated {
static BOOL firstTime = YES;
if (firstTime) {
//do stuff that takes some time (that's why I show the indicator)
MailViewController *controller = [[MailViewController alloc] init];
if (controller)
[self presentModalViewController:controller animated:YES];
firstTime = NO;
} else {
[self dismissModalViewControllerAnimated:YES];
}
}
Since the first view pops up again, the user can see the indicator one more time, after the second view is closed - and that is not what I want.
What am I missing here? What would be the better way to do this?
I would do something like this. Make a navigationController, and make the first view as the root controller. Then do something like this:
FirstView.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
}
- (void) nextView { // however you get to your next view, button/action/etc.
UIViewController *screen = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
[self.navigationController pushViewController:screen animated:YES];
}
Then in the second view:
SecondView.m
- (void) nextView { // however you get to your next view, button/action/etc.
UIViewController *screen = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
[self.navigationController pushViewController:screen animated:YES];
}
And finally in the rootview:
RootView.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *navStack = [NSArray arrayWithObject:self];
self.navigationController.viewControllers = navStack;
[self.navigationController setNavigationBarHidden:NO];
}
This will make your RootView the new rootview of the NavigationController.
self.navigationController.viewControllers
is the array with all the ViewControllers that are on the navcontrollers stack. The first object is the rootcontroller. If we replace the whole array with our own array, it knows only one item. You CAN go back by dismissing if that's what you want though. This isn't the prettiest way of doing it, but it's not the worst either.
I have done a sample app with UISplitViewController studying the example they have provided. I have created three detailviews and have configured them to change by the default means. Either using the left/master view in landscape AND using the popover in the portrait orientation.
Now I am trying to move to another view(previous/next) from the currentView by using left/right swipe in each view. For that, what I did was just created a function in the RootViewController. I copy-pasted the same code as that of the tablerow selection used by the popover from the RootViewController. I am calling this function from my current view's controller and is passing the respective index of the view(to be displayed next) from the current view. Function is being called but nothing is happening.
Plz help me OR is anyother way to do it other than this complex step? I am giving the function that I used to change the view.
- (void) rearrangeViews:(int)viewRow
{
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
if (viewRow == 0) {
DetailViewController *newDetailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (viewRow == 1) {
SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc] initWithNibName:#"SecondDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (viewRow == 2) {
ThirdDetailViewController *newDetailViewController = [[ThirdDetailViewController alloc] initWithNibName:#"ThirdDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
if (rootPopoverButtonItem != nil) {
[detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
[detailViewController release];
}
I have googled and found a nice approach. They use a UINavigationController on the detail view to push new views. You could use this same solution for your project.
http://www.cimgf.com/2010/05/24/fixing-the-uisplitviewcontroller-template/