How to populate a cell in UITableView with an edited content? - ios

Maybe I didn't ask it properly, because I'm not really sure how, so I will explain myself:
I have a simple notes app with two VC's:
table view controller - to list all the notes.
view controller - to create new notes.
In the table vc I have an unwindToList method that create an instance of the create notes page to get the note object that will be passed and if its not nil I will add it to the notes array and reload the data;
- (IBAction) unwindToList: (UIStoryboardSegue *) segue
{
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (note != nil) {
[self.notes addObject:note];
[self.tableView reloadData];
}
}
and an prepareForSegue method that will identify if this segue is a note segue (this is the segue I JUST want to preform editing in the create note page and when a user taps the save button, to save it in the same cell that the segue came from...):
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(UITableViewCell *)sender
{
if ([[segue identifier] isEqualToString:#"noteSegue"]) {
NMCreateNotesViewController *destination = [segue destinationViewController];
NSInteger indx = [self.tableView indexPathForCell:sender].row;
NMNote *note = self.notes[indx];
destination.passedInString = note.content;
}
}
In the view controller that create the notes I have a prepareForSegue method that looks like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton) return;
if (self.textField.text.length > 0) {
self.note = [[NMNote alloc] init];
self.note.content = self.textField.text;
}
}
Now, my problem is that when i'm editing a note from the noteSegue i'm creating a new note with the edited content instead of populating the same cell of the segueNote with the new edited content...
this is how the problem looks like:
Please help me to figure this out :/
Appreciate it!

I don't quite understand your explanation.
You have a table view controller that is a master view controller and a note view controller that is a detail view controller.
The usual way to handle communications back from a detail view controller to it's master is to set up a delegate.
Define a delegate property in the detail (notes) VC that will point back to the master.
In the master's prepareForSegue, set destination.delegate = self.
Then, define a protocol for the delegate that the detail view controller will use to tell the master that the contents of a list item has changed.
You will probably need to tell the detail view controller the indexPath of the item that's being edited in the master-to-detail segue, and then before unwinding to the master, invoke a delegate method that gives the edited item to the master, along with it's indexPath so the master can save the changes and redisplay that cell.

Related

Need some insight to make a 3 UIButton menu in XCode that toggles and changes dataset in the main ViewController

I'm new on Stackoverflow and I'm currently learning XCode from scratch and I'm in a process of making a Single Page Application with options.
Anyone knows how to efficiently make a simple menu with multiple selectable UIButtons that make the main ViewController display different datasets depending on the selection in XCode?
Tried different things (creating SecondViewController for example but can't figure out how to pass data from it to main ViewController).
Any help will be greatly appreciated.
Refer this:
https://www.appcoda.com/storyboards-ios-tutorial-pass-data-between-view-controller-with-segue/
How to pass prepareForSegue: an object
Simple Test from above Answer Reference:
Simply grab a reference to the target view controller in prepareForSegue: method and pass any objects you need to there. Here's an example...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
REVISION: You can also use performSegueWithIdentifier:sender: method to activate the transition to a new view based on a selection or button press.
For instance, consider I had two view controllers. The first contains three buttons and the second needs to know which of those buttons has been pressed before the transition. You could wire the buttons up to an IBAction in your code which uses performSegueWithIdentifier: method, like this...
//When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
[self performSegueWithIdentifier:#"MySegue" sender:sender];
}
// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"MySegue"]) {
// Get destination view
SecondView *vc = [segue destinationViewController];
// Get button tag number (or do whatever you need to do here, based on your object
NSInteger tagIndex = [(UIButton *)sender tag];
// Pass the information to your destination view
[vc setSelectedButton:tagIndex];
}
}
Hope this help but please go through refernces!

Multiple buttons to one Table View

Can someone point me in the right direction? I have one View Controller with multiple buttons. I want the button presses to open my custom one Table View Controller and load the data dynamically. I know I could make multiple Table View Controllers for each button press, but I was thinking there has to be a way to do this dynamically. Let me be clear that another view will determine which data to load into the Table View Controller. I'm new to iOS and Objective-C, but not programming, so take it easy on the rocket science answers. Let me know if you need to see some code.
Basically I have 4 buttons on one View Controller that when pressed will determine what data to load on the Table View. Let's keep it simple for now and just say that the data is 4 NSMutable Arrays.
EDIT:Based on babygau's post this is what I came up with:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"allCattleSegue"]) {
CattleTableViewController *controller = segue.destinationViewController;
controller.cattleArray = [[NSMutableArray alloc] initWithObjects:#"cattle1",#"cattle2",#"cattle3", nil];
}
else if ([segue.identifier isEqualToString:#"bullsSegue"]){
CattleTableViewController *controller = segue.destinationViewController;
controller.cattleArray = [[NSMutableArray alloc] initWithObjects:#"bull1",#"bull2",#"bull3", nil];
}
}
- (IBAction)allCattleTouchUpInside:(UIButton *)sender {
[self performSegueWithIdentifier:#"allCattleSegue" sender:self];
}
- (IBAction)bullsTouchUpInside:(UIButton *)sender {
[self performSegueWithIdentifier:#"bullsSegue" sender:self];
}
this gets the job done but now my navigation doesn't work properly when I press the back button. It gives me a blank screen.
UPDATE: Debugging I see that it is calling the prepareForSegue twice; once with the Controller as the sender and again with the button as the sender. Still attempting to understand how this works and how to resolve this navigation issue.
RESOLVED: Apparently I don't need the actions (TouchUpInside) wired up. Thanks for all of the help.
Hi just create one Viewcontroller and TableViewController. Set the tag fro all button and then create one #property int variable in TableViewController then do like this below..
Create common method to trigger for all button in UIControlTouchUpInside .Then in UITableViewController create int variable like this.
TableViewController.h file you create like this.
#property (nonatomic, assign) int buttonSelected;
ViewController.m create common method like this.
-(IBAction)commonMethod:(id)sender
{
TableViewController *tableVc = [[TableViewController alloc]initWithNibName:#"TableViewController" bundle:nil];
if(button.tag==0)
{
tableVC.buttonSelected = 0;
}
if(button.tag==1)
{
tableVC.buttonSelected = 1;
}
[self.navigationController pushViewController:tableVc animated:YES];
}
TableViewConroller.m file do this
-(void)viewDidLoad
{
[super viewDidLoad];
if(buttonPressed == 0)
{
tableDataSourceArray = ...
}
else if (buttonPressed == 1)
{
tableDataSourceArray = ...
}
}
I hope it helpful for you..
Assume that your table has tableViewData is an array.
In each button action, you use the following pattern code:
[self performSegueWithIdentifier:#"YOUR_IDENTIFIER" target:sender];
Implement the following segue delegate method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
YOURCUSTOMTABLEVIEWCONTROLLER *tableVC= segue.destinationViewController;
tableVC.tableViewData = YOUR_CORRESSPONDING_MUTABLE_ARRAY;
[tableVC.tableView reloadData];
}
That's it, you will have tableView display dynamically based on which button you click.
Notice: you have to create 4 segue between View Controller corresponding to 4 buttons and name the identifier for each segue. e.g #"fromButton1toTableVC", #"fromButton2toTableVC" and so on...
You could pass something like the button label or an identifier telling which mutable array to use.
if your doing the transition in code using a segue in your prepareForSegue method you can pass the value to the destination TableViewController i.e.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UITableViewController *controller = segue.destinationViewController;
controller.buttonTitle = sender;
}
Then in the button handler
[self perfomSegue:#"segue" sender:buttonTitle];
assign tag for each button. according to tag you can populate different data in table.simply take only one array.populate data to that array according to tag
if(button.tag==0)
{
//array=#[..];
}
if(button.tag==1)
{
//array=#[..];
}
.
.
.
Now use this array in cellForRowWithIndexPath delegate method

UITableView with toolbar and multiple segues

I have a simple storyboard file with a table view inside a navigation controller. If you cick one of the cells it goes to the details view. Great.
Then I tried adding a toolbar button and hooking it up to my table view controller. The button and the seque seems to work fine, except now, when i click on one of the table cells, the modal view is triggered.
So it seems I have done something wrong, but I don't understand what.
// called by pressing the add button in the toolbar
- (IBAction)showAddEventView:(id)sender {
[self performSegueWithIdentifier:#"showAddEvent" sender:sender];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showAddEvent"]) {
AddEventVC *addEventVC = [[AddEventVC alloc] init];
// set some property
} else {
EventIndexVC *eventIndexVC = [segue destinationViewController];
eventIndexVC.eventTitle = [self.events objectAtIndex: [[self.tableView indexPathForSelectedRow] row]];
}
}

performSegueWithIdentifier on didSelectRowAtIndexPath

With this code every time user click on any cell will perform the segue again and again , I am wondering how could I keep track of the loaded view to keep data when switching views and not an infinite new viewcontroler.
Thanks -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
[self.navigationController
performSegueWithIdentifier:#"rep" sender:self];
} else if (indexPath.row == 1) {
[self.navigationController
performSegueWithIdentifier:#"rep1" sender:self];
}
}
Try my other approach first, but if you really need a maintain a pointer to the new view controller you could try this approach. This should perform the segue once, creating the reference to the view controller which will subsequently be manually pushed into the navigation controller.
Override the view controller methods:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
if(self.myViewController == nil){
return YES;
}else{
[self.navigationController pushViewController:self.myViewController animated:YES]
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
self.myViewController = (MyViewController*)segue.destinationViewController;
self.myViewController.customVar = 1; //perform initial customization
}
What do I know though, I've never used Storyboards...
Perhaps an alternative to maintaining a reference to the view controller would be to customize the view controller prior to seque.
Override the view controller method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
MyViewController *targetController = (MyViewController*)segue.destinationViewController;
targetController.customVar = 1;
}
The default implementation of this method does nothing. Your view controller overrides this method when it needs to pass relevant data to the new view controller. The segue object describes the transition and includes references to both view controllers involved in the segue.
You don't need to take new View controller each and every time for each row unless and until you want it customized. This will make large amount of view controllers on storyboard.
So, Just command drag segue from controller A to B. Example: if A is tableViewController and B is simple VC where you are displaying data of table's row then command drag from whole tableViewController to B. Now this will act as common segue with one identifier only.
So in your code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Set your B's label/property etc to cell's data or anything so that it will reflect in B.
B.label = cell.text;
[self performSegueWithIdentifier:#"Identifier" sender:self];
}
Hope this helps.
I think you can keep the new viewController's pointer. Then next time you can use it like this:
[self.navigationController pushViewController:thePointer animated:YES]
I very seldom use Storyboard. So I am not sure it will work.

How do I set the title on the destination view controller during prepareForSegue:

I want to simply set the title on my destination view controller so that it shows in its navigation controller's navigation bar in the prepareForSegue: method however setting its title or navigationItem like so:
[segue.destinationViewController setTitle:#"doesn't work"];
[segue.destinationViewController.navigationItem setTitle:#"this either"];
doesn't work possibly because the destination's view controller's view isn't loaded yet. Can I do this without creating a custom destination view controller?
Try accessing your ViewController that is embedded in the UINavigationController like this.
First you give your segue an identifier in the interface builder, then you access the segue in the prepareForSegue method and set the title by accessing the topViewController property of the navigation controller you segue to.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"yourSegueIdentifier"]) {
UINavigationController *navController =
(UINavigationController*)[segue destinationViewController];
YourViewController *destViewController =
(YourViewController* )[navController topViewController];
destViewController.navgationItem.title.text = #"Your new title";
}
}
This is for a segue into another UITableView
Set a public NSString property in the destination UITableViewController file.
#property (strong, nonatomic) NSString *navBarTitle;
Override the setter in the .m file just to be sure.
- (void) setNavBarTitle:(NSString *)navBarTitle
{
_navBarTitle = navBarTitle;
}
In the originating tableView's segue method, pass whatever string you need in the title.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString: #"userDetails"]) {
UsersActivitiesTableViewController *destinationController = segue.destinationViewController;
//Get the index path of the cell the user just clicked
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
//Grab the object from the array of users if the next view requires a specific title for a user name etc.
UserMO *thisUser = [self.users objectAtIndex:indexPath.row];
//Pass the string you want as the title to the public NSString property
destinationController.navBarTitle = thisUser.name;
}
}
And now for the important bit....
In the destination controller, get the top controller of the view and set the title property, after the view is loaded, and before it has been displayed:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController topViewController].title = self.navBarTitle;
}
If you want a static title this can now (i.e., in Xcode 4.6.3) this can be done in Storyboard simply by setting the title in the nav bar on the relevant view controller.
If however you want the nav bar title to change according to what view is being segued to, e.g., a detail of a particular table row, as far as I know that needs to be set programmatically.
It took me FOREVER (newbie, sigh!) to figure out how to modify Julian Vogels' correct answer to call the key I wanted to use. Here's what worked:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"DetailSegue"]) {
// Fetch Item
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDictionary *item = [self.groceries objectAtIndex:[indexPath row]];
// Configure Detail View Controller
TPDetailViewController *vc = [segue destinationViewController];
vc.navigationItem.title = [item objectForKey:#"name"];
[vc setItem:item];
}
If the segue is a push segue - which it should be if you're using a UINavigationController - then the destination view controller is automatically added to the window hierarchy, and you don't even need to identify the UINavigationController:
if ([segue.identifier isEqualToString:#"yourSegueNameHere"]) {
[segue.destinationViewController setTitle:#"yourTitleHere"];
}

Resources