How to switch from one view controller to another in a chain - ios6

I have a initial view controller, from which i need to push to first view controller. on back click of first view controller instead of going back to initial view controller i need to go to a third view controller. from back click on third view controller it should go back to initial view controller. Could anyone suggest me how to do it in ios6 and also in ios7.

Call setViewControllers:animated: after the push, to insert the middle view controller into the stack.

there are many other way to do but i prefer this one:
for that you have to add programmatically navigation bar button as "back" at first view controller(in your case) but in this case you required back_arrow image:
UIImage *faceImage = [UIImage imageNamed:#"back_arrow.png"];
UIButton *face = [UIButton buttonWithType:UIButtonTypeCustom];
face.bounds = CGRectMake( 10, 0, faceImage.size.width, faceImage.size.height );
[face addTarget:self action:#selector(handleBack) forControlEvents:UIControlEventTouchUpInside];
[face setImage:faceImage forState:UIControlStateNormal];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:face];
self.navigationItem.leftBarButtonItem = backButton;
[self.navigationItem setHidesBackButton:YES animated:YES];
[self.navigationItem setLeftBarButtonItem:nil animated:NO];
[self.navigationItem setBackBarButtonItem:nil];
-(void)handleBack
{
//got third view controller here
}
may it will help you.

Related

How to `presentViewController` with custom animation on iOS 6?

How can I have custom animation for view controller presented with presentViewController method on iOS 6+ ? I want the new VC's view to zoom in from some point.
I'm using the following routine to fade in new controller:
CATransition* transition = [CATransition animation];
transition.duration = 1;
transition.type = kCATransitionFade;
transition.subtype = kCATransitionFromBottom;
[self.view.window.layer addAnimation:transition forKey:kCATransition];
[self presentViewController:viewController animated:NO completion:nil];
But I'm not sure how and whether it's possible to zoom in view this way.

How can I present a ModalViewController from a UIActivity item picked from UIActivity View Controller?

I am working on an app that presents some data in a detailViewController. I have a rightBarButton in the navbar that presents a UIActivityViewController that is filled with my own UIActivity sublclassed items. Most of them work fine as they are just changing a small aspect to the data from the detail view, but I need one of them to open a modalViewController when selected. I keep getting the following warning from the console.....
Warning: Attempt to present <UINavigationController: 0x1fd00590>
on <UITabBarController: 0x1fde1070> which is already presenting <MPActivityViewController: 0x1fd2f970>
I suppose it is worth noting that the app doesn't crash but the modal view doesn't appear either. I am assuming that the UIActivityViewController is a modal view itself and you can only display one of those at a time so the task is to figure out how to perform my segue after the ActivityView has disappeared, but thats where I am stumped. I welcome any help, thoughts or feedback. I've tried google but haven't had much luck, I assume because The UIActivityViewController is so new.
Here is my setup so far,
my UIActivity objects have a delegate set to the detailViewController for a custom protocol that lets the detailViewController perform the data changes and then update its view.
for the activities in question that should present the modalView controller I have tried a few approaches that all get the same warning.
None of These Works!!!
1) simply tried performing segue from my delegate method
- (void) activityDidRequestTransactionEdit
{
NSLog(#"activityDidRequestTransactionEdit");
[self performSegueWithIdentifier:#"editTransaction" sender:self];
}
2)tried setting a completion block on the UIActivityViewController and having my delegate method set a bool flag that the modal view should be shown(self.editor)
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) {
NSLog(#"completed dialog - activity: %# - finished flag: %d", activityType, completed);
if (completed && self.editor) {
[self performSegueWithIdentifier:#"editTransaction" sender:self];
}
}];
3) subclassing the UIActivityViewController itself, giving it the detailView as a delegate, and overriding it's dismissViewControllerAnimated: method with my own completion block
- (void) dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
{
[super dismissViewControllerAnimated:flag completion:^{
[self.MPActivityDelegate activityDidRequestTransactionEdit];
}];
}
The working Solution
In the UIActivity subclass you need to override this method like so
- (UIViewController *) activityViewController {
MPEditMyDataViewController *controller = [[MPEditMyDataViewController alloc] init];
controller.activity = self; // more on this property below
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
return navController;
}
in your MPEditMyDataViewController.h (the view controller the chosen action should produce)
You need a property back to the activity subclass like so
#property (strong, nonatomic) MPEditMyDataActivity *activity;
in your MPEditMyDataViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(cancel)];
self.navigationItem.leftBarButtonItem = cancelButton;
}
// here's how you dismiss the view controller when you are done with it
// after saving the changes to your data or whatever the view controller is supposed to do.
-(void) cancel
{
NSLog(#"Cancel Button Pushed");
[self.activity activityDidFinish:YES];
}
#end
Did some more documentation digging and found this method for UIActivity subclassing
- (UIViewController *) activityViewController
it gets my view controller to pop up like I wanted by returning it from here instead of trying to segue it from my detailViewController. Now to figure out how to dismiss it when I'm done with it!!!!

collectionView, didSelectItemAtIndexPath issue

I have an interesting issue with collectionView, specifically, didSelectItemAtIndexPath.
My app has one particular view with a background image, which is accessed via an SQL. Within that view is a popover, with a collectionView, to change the parent view's background, and access other "sets" available for purchase.
My issue is with the changing of the background. All items display correctly in the collection view and the parent's background will change as it should. The problem is that the item selected is not the one that displays, even though via NSLog, I can see that the correct image is being selected and passed back to the parent. There is a corresponding NSLog in the parent, which shows the same image id as the popover's NSLog.
The first item in the collectionView, when tapped, will change the background of the parent to white, as if there was no image available. Tapping the second cell will display the first cell's image. Tapping the third cell will display the second cell's image... and so on. There are 15 images available to select from.
This is the didSelect method:
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([_currentView isEqualToString:#"New_Journal"])
{
MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication.sharedApplication delegate];
// to get the variable back to the parent
appDelegate.loadBackgroundID = indexPath.row;
// interact with the SQL via _settingsDao
[_settingsDao updateJournalBackgroundId:_journalId withBackgroundId:appDelegate.loadBackgroundID];
NSLog(#"Selected background: %d", indexPath.row);
// notification to let EntryView know the background has changed
[NSNotificationCenter.defaultCenter postNotificationName:#"aBackgroundChanged" object:self];
}
}
Edit to show SQL interaction method:
-(void)updateJournalBackgroundId:(int)journalID withBackgroundId:(int)newBackgroundId
{
NSString *query = #"UPDATE BgIconBorderSettings SET background_id = ? WHERE journal_id = ?";
FMDatabase *db = [dbUtils sharedDB];
[db executeUpdate:query,[NSNumber numberWithInt:newBackgroundId],[NSNumber numberWithInt:journalID]];
if([db hadError])
{
NSLog(#"Error %d: %#",[db lastErrorCode],[db lastErrorMessage]);
}
}
Anyone have any ideas on how to get the correct image of the tapped cell to display? Thanks for any assistance in solving this issue.
As jhilgert pointed out... it was the SQL database. It started at 1 and not 0. Changed the ids and it works as expected.

Multiple TableViews in a Single View Xcode

I have one view that has two tableviews, I want one of them to be a twitter feed and the other an RSS feed. The problem is they show up exactly the same, same content. I have tried using another controller, but I cannot do that because i cannot figgure it out.
Not sure if you are still looking for the answer to your question, but in any case it may be helpful for others too. I have tried the following with success:
You can use a separate tableviewcontroller for each tableview. In your viewDidLoad you can alloc init your tableviewcontrollers and then set the tableview's datasource and delegate to be your respective tableviewcontrollers. Finally, set the view of your controllers to be the tableview of your tableview controller. The following code shows what I mean:
- (void)viewDidLoad
{
[super viewDidLoad];
// ...
if(!self.tweeterTableViewController)
{
self.tweeterTableViewController = [[TweeterTableViewController alloc] init];
}
if(!self.rssTableViewController)
{
self.rssTableViewController = [[RssTableViewController alloc] init];
}
[self.tweeterTableView setDataSource:self.tweeterTableViewController];
[self.tweeterTableView setDelegate:self.tweeterTableViewController];
self.tweeterTableViewController.view = self.tweeterTableViewController.tableView;
[self.rssTableView setDataSource:self.rssTableViewController];
[self.rssTableView setDelegate:self.rssTableViewController];
self.rssTableViewController.view = self.rssTableViewController.tableView;
// ...
}

How to properly add and delete objects to tableview with custom tableviewcells?

I'm currently developing an app that behaves like the Messages.app. The MasterViewController is the main view where it loads a table of the contact name, time and a snippet of the most recent message. When you tap a specific cell, it slides to the DetailViewController where it loads the messages I sent to the contact with the latest, complete message. Hitting the back button goes back to the MasterViewController. Tapping the rightBarButtonItem opens up a ComposeViewController (modal) where the user can compose a message to a specific contact. The difference of this app to the default Messages.app is that it has a delay timer before the message is sent. The ComposeViewController has a textfield to input the message, button to select a contact, button to pick a time delay, button to send, button to cancel the timer, and a button to dismiss the ModalViewController.
I removed the ability to send an actual SMS message entirely. I just presented the user with an alert view telling him/her that the message was sent and if he/she wants to compose a new one. Hitting Cancel will dismiss the ModalViewController and go back to the MasterViewController.
Problem is, I can't make the rows appear on the table and also have the ability to add and remove cells in the table.
Here's some code inside my MasterViewController's viewDidLoad:
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Delete button to delete messages
UIBarButtonItem *deleteBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemTrash
target:self
action:#selector(deleteText)];
self.navigationItem.leftBarButtonItem = deleteBarButtonItem;
// Compose button to go to compose messages
UIBarButtonItem *composeBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCompose
target:self
action:#selector(composeText)];
self.navigationItem.rightBarButtonItem = composeBarButtonItem;
[deleteBarButtonItem release];
[composeBarButtonItem release];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *message = [defaults objectForKey:kMessageText];
NSString *contactname = [defaults objectForKey:kContactNameText];
NSString *timestamp = [defaults objectForKey:kTimeStampText];
[messageDetails initWithObjectsAndKeys:contactname, kContactNameKey, message, kContactMsgKey, timestamp, kContactTimeKey, nil];
NSMutableArray *messageInfo = [[NSMutableArray alloc] initWithObjects:messageDetails, nil];
self.messagesList = messageInfo;
[messageInfo release];
[super viewDidLoad];
Here's the code in cellForRowAtIndexPath:
CustomCellViewController *customCell = (CustomCellViewController *)[tableView dequeueReusableCellWithIdentifier:#"CustomCellViewController"];
if (customCell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCellViewController"
owner:self
options:nil];
for (id oneObject in nib) if ([oneObject isKindOfClass:[CustomCellViewController class]])
customCell = (CustomCellViewController *)oneObject;
}
NSUInteger row = [indexPath row];
NSDictionary *messages = [self.messagesList objectAtIndex:row];
customCell.nameLabel.text = [messages objectForKey:kContactNameKey];
customCell.nameLabel.textColor = [UIColor whiteColor];
customCell.messageLabel.text = [messages objectForKey:kContactMsgKey];
customCell.messageLabel.textColor = [UIColor lightGrayColor];
customCell.timeLabel.text = [messages objectForKey:kContactTimeKey];
customCell.timeLabel.textColor = [UIColor blueColor];
customCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return customCell;
Here's the code for deleting cells:
- (void)tableView:(UITableView *)tableView commitEditingStyle(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]withRowAnimation:UITableViewRowAnimationFade];
[messagesList removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
Your final code snippet where you are creating a new instance of the master view controller is the problem.
This is not the view controller you are looking for. Since you've presented the detail view controller modally, you can access the master controller via the parentViewController property of the detail controller:
MasterViewController *master = (MasterViewController*)self.parentViewController;
Other design patterns that are typically used in this situation:
Create the new object in your master controller and insert the row in your table before passing the new object to the detail controller for updating
Create a delegate protocol for the detail controller, which your master controller conforms to. Set the detail controllers delegate to the master controller when pushing it
The latter is almost what you are doing for all practical purposes, except your detail controller knows more than it needs to about the master controller (i.e you are importing the whole master .h file rather than just knowing it conforms to a protocol).
Regarding your data structure, I don't understand how you expect to have multiple rows in here - you store one message in user defaults and then create an array with that message. I know you don't intend to use defaults to store this in the end, but I would expect to see an array of dictionaries stored in defaults under a single key, and then each dictionary represents a row in your table, with the various details stored as strings in the dictionary against your message, contact name keys etc.
You have to make a mutable version of the array returned from defaults as it always returns an immutable array.
In your cellForRow... method you'd then get the appropriate dictionary from the array and populate the cell from it.
When adding a new row you'd create a new dictionary to pass to your detail controller.
When deleting a row you'd remove the relevant dictionary from the array.

Resources