Show or dismiss a specific ViewController after performing an action - objective-c

I want to show a specific ViewController (or dismiss) a View after performing an IBAction in my iPhone App. I've tried
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];
However this does not appear to do anything once the action has been performed.
A bit more information:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (selectedCell.tag == 1)
{
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:#"Are you sure you want to delete this project?"
delegate:self cancelButtonTitle:#"No" destructiveButtonTitle:#"Yes, I’m Sure" otherButtonTitles:nil];
[actionSheet showInView:self.view];
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex != [actionSheet cancelButtonIndex])
{
[self.tableView beginUpdates]; // Avoid NSInternalInconsistencyException
// Delete the project object that was swiped
Project *projectToDelete = self.project;
NSLog(#"Deleting (%#)", projectToDelete.name);
[self.managedObjectContext deleteObject:projectToDelete];
[self.managedObjectContext save:nil];
}
}
I want the current view to disappear when a user presses the Yes button on the actionsheet.

// Assume we are inside a UIViewController (or a subclass)
DestinationController *destinationController = [[DestinationController alloc] init];
[self presentModalViewController:destinationController animated:YES];
...
// Assume we are now in destination controller
// Dismiss
[self dismissModalViewControllerAnimated:YES];

I needed to go all the way back to the first (or, root) view in my navigation stack.
All I need to do was use this method:
[controller.navigationController popToRootViewControllerAnimated:YES];

Another way to show and dismiss a view controller is with pushViewController and popViewController.
To show a viewController:
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
// Uses a horizontal slide transition. Has no effect if the view controller is already in the stack.
And to dismiss:
-(UIViewController *)popViewControllerAnimated:(BOOL)animated; // Returns the popped controller.

Related

NSUserDefaults not appearing first appearence

So I've been learning iOS for the past couple months and have recently ran into this problem. I have a settings screen inside my app after a log in process that should save some basic information pertaining to the user. The issue is when the view first appears from a tab bar controller, the static grouped table view is blank with none of the information available for the cell.detailLabel.text. I used NSLog to discover that at first when retrieving the objects from keys, they are null. However, when I select a cell to change it's information and push on another view controller, I can then go back and all the values will appear from previous inputs saved to NSUser defaults. I was curious why this happens and for a solution. Thanks
#import "SettingsController.h"
#import <Parse/Parse.h>
#import "LogInViewController.h"
#import "AddSettings.h"
#import "AddUrination.h"
#import "ChooseAlarmController.h"
#interface SettingsController ()
#end
#implementation SettingsController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
UIBarButtonItem *addUrination=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addUrinationView:)];
self.navigationItem.rightBarButtonItem=addUrination;
/*Rename the back button which every pushed on controller will have*/
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
NSLog(#"view loaded");
}
-(void)viewWillAppear:(BOOL)animated
{
/*Everytime view appears, we want to repopulate the table with updated content*/
NSLog(#"Settings View appeared,Load the keys");
/*Load every cell with appropiate details*/
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
NSIndexPath *path=[NSIndexPath indexPathForRow:0 inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"FirstNameKey"];
NSLog(#"%#",cell.detailTextLabel.text);
path=[NSIndexPath indexPathForRow:1 inSection:0];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"LastNameKey"];
path=[NSIndexPath indexPathForRow:2 inSection:1];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"NumberOfUrinationsKey"];
[self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:YES];
path=[NSIndexPath indexPathForRow:0 inSection:1];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"StartingAlarmKey"];
path=[NSIndexPath indexPathForRow:1 inSection:1];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"FinalAlarmKey"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)addUrinationView:(id)sender
{
[self performSegueWithIdentifier:#"AddUrinationSegue" sender:self];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// If Log Out Button is selected
if(indexPath.row==0 && indexPath.section==2){
NSLog(#"Log Out selected");
[PFUser logOut];
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Are You Sure?" message:#"If you would like to change your mind, press cancel. Otherwise choose log out" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Log Out", nil];
[alert show];
}
NSLog(#"Selected row is %ld %ld", (long)indexPath.section,(long)indexPath.row);
/*Segue depends on which cell is selected. First section segues to text input (AddSettings.h)*/
if((indexPath.section==0 && indexPath.row<2) || (indexPath.section==1 && indexPath.row==2)){
[self performSegueWithIdentifier:#"AddSettingSegue" sender:self];
}
/*Choose alarm controller is selected*/
if(indexPath.section==1 && indexPath.row<2){
[self performSegueWithIdentifier:#"AddAlarmSegue" sender:self];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if([segue.identifier isEqualToString:#"AddSettingSegue"]){
AddSettings *settingsController=[segue destinationViewController];
/*index path contains both the section and row of the selected cell*/
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSLog(#"Section:%ld Row:%ld",(long)indexPath.section,(long)indexPath.row);
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
settingsController.titleOfController=cell.textLabel.text;
}
if([segue.identifier isEqualToString:#"AddUrinationSegue"])
{
AddUrination *addUrinationView=[segue destinationViewController];
}
if([segue.identifier isEqualToString:#"AddAlarmSegue"]){
ChooseAlarmController *alarm=[segue destinationViewController];
NSIndexPath *indexPath=[self.tableView indexPathForSelectedRow];
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
alarm.titleOfController=cell.textLabel.text;
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex==1){
[self performSegueWithIdentifier:#"UnwindToLogIn" sender:self];
}
}
#end
Add [super viewWillAppear:animated] to the top of your viewWillAppear: override. According to Apple's documentation for viewWillAppear:,
"If you override this method, you must call super at some point in your implementation."
While your application generally won't crash or anything if you omit it, important initialization performed by the base class will not occur unless you call [super viewWillAppear:animated], which may result in unexpected behaviour, such as label values not appearing in your table view cells.
As a best practice, you should always call the super method whenever you override one of Apple's methods, unless you explicitly do not want the default behaviour to occur (eg. overriding touchesBegan:withEvent:). Though there are exceptions, generally overridden initialization methods like viewDidLoad and viewWillAppear: should call their super method at the beginning of the method, while overridden teardown methods like viewWillDisappear: should call their super method at the end.

Edit Item in Bottom Toolbar Xcode and Objective C

I have a Navigation Controller. I want to put the edit button on the bottom in the toolbar instead of in the top navigation bar.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
The problem I have is that when I add the edit button to the Bottom Toolbar. like this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[self.christmasGifts removeGiftAtIndexPath:indexPath];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:YES];
//Do not let the user add if the app is in edit mode.
if(editing)
self.navigationItem.rightBarButtonItem.enabled = YES;
else
self.navigationItem.rightBarButtonItem.enabled = YES;
}
And then link the edit button setEditing: in the toolbar it does not show a done button like the Edit button in the top navigation. it just stays the same.
But you can delete an item, but you cannot reset the state to normal again with the bottom button.
I need to be able to go back to the previous controller from this Navigation Controller. but the edit button hides the back button.
Edit.
I know I can by code add the toolbar.
UIBarButtonItem *editButton = [[UIBarButtonItem alloc]
initWithTitle:#"Edit"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(setEditing:)];
[[UIBarButtonItem appearance] setTintColor:[UIColor colorWithRed:70/255.0f green:155/255.0f blue:19/255.0f alpha:1.0]];
NSArray *arrBtns = [[NSArray alloc]initWithObjects:editButton,anotherButton, nil];
self.toolbarItems = arrBtns;
and
[self.navigationController setToolbarHidden:NO];
or even
UIToolbar *toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 500, 400, 40)];
[self.tableView addSubview:toolBar];
In your ViewController.h, declare (and connect them in XIB)
#property (strong, nonatomic) IBOutlet UIToolbar *toolbar;
#property (strong, nonatomic) IBOutlet UIBarButtonItem *toolbarbutton;
- (IBAction)toolbarbuttonTouched:(id)sender; // Connect with UIBarButtonItem in XIB
In your ViewController.m, paste down the following function.
- (IBAction)toolbarbuttonTouched:(id)sender
{
if ([self.toolbarbutton.title isEqualToString:#"Edit"])
{
[self.tableView setEditing:YES animated:YES];
self.toolbarbutton.title = #"Done";
}
else
{
[self.tableView setEditing:NO animated:YES];
self.toolbarbutton.title = #"Edit";
}
}
And you are all set to go.
Points
Your UIBarButtonItem's initial value for property title must be
set to "Edit"
Code for editingStyle == UITableViewCellEditingStyleDelete should
be working perfectly
EDIT
You don't need the following code:
self.navigationItem.leftBarButtonItem = self.editButtonItem;
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:YES];
//Do not let the user add if the app is in edit mode.
if(editing)
self.navigationItem.rightBarButtonItem.enabled = YES;
else
self.navigationItem.rightBarButtonItem.enabled = YES;
}
Let me know, If it works for you or not.
I was able to do this more simply by using UIViewController's editButtonItem method:
- (void)viewDidLoad {
[super viewDidLoad];
// Place table view Edit button in toolbar, after existing buttons.
NSMutableArray *items = [self.toolbarItems mutableCopy];
[items addObject:self.editButtonItem];
[self setToolbarItems:items animated:YES];
}
This gets the existing array of toolbar buttons (if any) and makes a mutable copy of the array so it can be changed. It then adds UIViewController's built-in Edit button to the toolbar.
The result is a functioning Edit/Done toolbar button that toggles Edit mode on and off, without having to write your own action method to handle that.

iOS 5 Black screen after segue

I have an iOS 5 application with a storyboard and two scenes. Scene 1 is a selection list while Scene 2 shows details for each selection
In Scene 1 I need to pass a variable and I do that with:
//Handles the selection
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
Guests *myGuests =[guestList objectAtIndex:[indexPath row]];
selectedGuest = [[NSString alloc] initWithFormat:#"You have selected %#", myGuests.guestID];
[self performSegueWithIdentifier:#"TGG" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"TGG"]){
GuestDetailsViewController *vc = [segue destinationViewController];
[vc setGuestSelected:selectedGuest];
}
}
In Scene 2 (details) I use this to verify that the right variable was received like this
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
NSString *msg = [[NSString alloc] initWithFormat:#"You have selected %#", guestSelected];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Selection" message:msg delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
nameCell.textLabel.text= msg;
[super viewDidLoad];
}
All of this works fine and the alert box shows the right variable and there is a transition to the new scene. HOWEVER, the alert box displays a total of 5 times over & over and, once completed, the whole window is black. Nothing from my scene (Scene 2) is displayed at that point. So I know I have the right segue, it transitions as desired, I just can't see anything on my screen.
i ran into a situation very similar. i had unintentionally un-commented the method:
-(void)loadView
i believe this method overrides the IB interface and created it from this code instead. check to make sure it is either removed or commented out IMHO.

Using addSubView or presentModalViewController in a standard method with paramaters?

I'm trying to reuse code, I have some tutorial view controllers / views, which I would like to call from an action sheet. However, the calling views are different. Sometimes the tutorial view(s) would need to be added as a subview and sometimes they would be added to the navigation controller.
How can I expand my standard function to cater for these two different situations ?
You can see what I'm having to do instead, which means duplicate code :(
I have a class called which holds the standard code, I want to add calls to views here directly.
-(void)showHelpClickButtonAtIndex:(int)buttonIndex:(UIView *)vw {
if (buttonIndex == CommonUIHelpPagesBtnIdx) {
// do nothing
} else if (buttonIndex == 0) {
NSLog(#"Tutorial here");
}
}
I use in one view like this ...
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex {
CommonUI *cui = [CommonUI alloc];
[cui showHelpClickButtonAtIndex:buttonIndex:self.view];
[cui release];
if (buttonIndex == CommonUIHelpPagesBtnIdx) {
UIViewController *theController = [[HelpViewController alloc]
initWithNibName:#"HelpView"
bundle:nil onPage:HelpPageCalcBalance];
[self.navigationController.topViewController
presentModalViewController:theController animated:YES];
[theController release];
}
}
And is another view like this...
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex {
[cui showHelpClickButtonAtIndex:buttonIndex:self.view];
if (buttonIndex == CommonUIHelpPagesBtnIdx) {
theController = [[HelpViewController alloc] initWithNibName:#"HelpView"
bundle:nil onPage:HelpPageGettingStarted];
[self.view addSubview:theController.view];
}
}
Maybe the actionSheets could share one same delegate that would be a root viewController or the appDelegate that would know what to do according to it's current state. Hence the same actionSheet method would be used in both case.
If you put your appDelegate which can always be reached as the actionSheetDelegate, you should be able to gain control on every way to present your view, either modally or not in any of your views + the window.
EDIT (re-Edited with your code): Maybe try this
MyAppDelegate.h:
#interface MyAppAppDelegate : NSObject <UIApplicationDelegate, UIActionSheetDelegate>
(...)
- (void) showHelp;
MyAppDelegate.m:
- (void) showHelp {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#""
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles: #"Tutorial", #"Help Pages", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[actionSheet showInView:window];
[actionSheet release];
}
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == CommonUIHelpPagesBtnIdx) {
UIViewController *theController = [HelpViewController alloc];
if ([[self lvc] superview] != nil) {
theController = [initWithNibName:#"HelpView"
bundle:nil
onPage:HelpPageGettingStarted];
[window addSubview:theController.view];
} else {
theController = [initWithNibName:#"HelpView"
bundle:nil
onPage:HelpPageCalcBalance];
UINavigationController * navController = [tabBarController selectedViewController];
[navController.topViewController presentModalViewController:theController animated:YES];
}
[theController release];
}
}
and in your viewControllers:
- (void)viewDidLoad {
[super viewDidLoad];
MyAppDelegate *delegate = (MyAppDelegate *) [[UIApplication sharedApplication] delegate];
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[infoButton addTarget:delegate
action:#selector(showHelp)
forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *infoItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton];
self.navigationItem.rightBarButtonItem = infoItem;
[infoItem release];
}
Didn't try it but it should work.

didSelectRowAtIndexPath problem

I have a problem that I had working in a test but now in a bigger application I can't seem to sort out.
First of I have a view that has six button each loads a different view I am using:
- (IBAction)showInfo2:(id)sender {
InfoViewController *Infocontroller = [[[InfoViewController alloc] initWithNibName:#"InfoView" bundle:nil] autorelease];
Infocontroller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:Infocontroller animated:YES];
}
This seems to be working fine, and loads the next section, in this case 'infoview'.
I then load a tableview and fill it full f data from an xml feed, this again is now working, (although was not an easy task for me!).
The problem comes when I know try and use:
Nothing seems to happen, ie, the new view is not loaded.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here -- for example, create and push another view controller.
SubInfoViewController *subInfoViewController = [[SubInfoViewController alloc] initWithNibName:#"SubInfoView" bundle:nil];
[self.navigationController pushViewController:subInfoViewController animated:YES];
[subInfoViewController release];
}
I know its being called because this works:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *message = [[NSString alloc] initWithFormat:#"You selected a row"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Row Selected" message:message delegate:nil cancelButtonTitle:#"Yes I did" otherButtonTitles:nil];
[alert show];
[message release];
[alert release];
}
Any help more than welcome, and please be gentle newbie :)
You're view is probably push into navigation stack but you can't see it because your parent view is modal.
You can't try to display your SubInfoViewController like this :
SubInfoViewController *subcontroller=[[SubInfoViewController alloc] initWithNibName:#"SubInfoViewController" withBundle:nil];
[self presentModalViewController:subcontroller animated:YES];
[subcontroller release];
If you want to keep a navigation logic in your app, you should not display your InfoViewController modally but present it in a common way in your navigation stack.
You can try to dismiss your modal view before pushing your SubViewController. In this case you must do something like this :
SubInfoViewController *controller=[[SubInfoViewController alloc] initWithNibName:#"SubInfoViewController" bundle:nil];
[self.parentViewController pushViewController:controller animated:YES];
[self dismissModalViewControllerAnimated:YES];
[controller release];
You'll receive a warning because parentViewController may not respond to pushViewController: animated: but with a NSLog you'll see that your parentViewController is actually a UINavigationController.
Hope this helps !
What exactly is the problem? Your code looks fine at first glance.