pass data from selected row to view controller - ios

I have a UITableView in a popover. When a user selects a row in the popover I am wanting it to close the popover and save some data in the cell to a variable in the parent view controller. What is the most efficient way to do this?

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
In this method you handle the user selection. For passing variables between view controllers from a UITableView to another ViewController read this great tutorial from ray wenderlich : http://www.raywenderlich.com/1797/how-to-create-a-simple-iphone-app-tutorial-part-1

Create a delegate in popover's table view controller and pass the variable to it as cell data
In .h of the popover's table view controller
#protocol PopoverTableViewControllerDelegate <NSObject>
- (void)didSelectRow:(NSString *)cellDataString;
#end
#interface PopoverTableViewController : UITableViewController
#property (strong, nonatomic) id<PopoverTableViewControllerDelegate> delegate;
#end
In the .m's didSelectRowAtIndexPath call the delegate and pass the cell data variable as
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate didSelectRow:cellDataString];
}
- (void)dealloc
{
[super dealloc];
[_delegate release];
}
Implement it in parent view controller in .h implement the PopoverTableViewControllerDelegate as
#interface ParentViewController : UIViewController <PopoverTableViewControllerDelegate>
#property (strong, nonatomic) NSString *cellDataString;
#end
and in .m implement the delegate as
- (void)dealloc
{
[super dealloc];
[_cellDataString release];
}
PopoverTableViewController *popoverTableViewController = [[[PopoverTableViewController alloc] init] autorelease];
popoverTableViewController.delegate = self;
- (void)didSelectRow:(NSString *)cellDataString
{
self.cellDataString = cellDataString;
[popOverController dismissPopoverAnimated:YES];
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ParentViewController *parent = [[ParentViewController alloc] initWithNibName:#"ParentViewController" bundle:nil];
parent.variable = //do something you want
[self.navigationcontroller pushViewController:parent animated:YES];
}
Something like this... Hope this helps...

Related

In Split view controller: Call detailed view controller method from master view controller

In my MasterViewController uitabelview did select method change the DetailedViewController view.
My problem is when i change the view in DetailedViewController need to save the textfield values if user not saved manually.
How can i check this from MasterViewController or any idea to detect master view did select method called from DetailedViewController.
thanks in advance.
in your MasterViewController.h
#protocol CellSelectionDelegate <NSObject>
-(void)rowSelected:(NSIndexPath *)indexPath;
#end
#interface MasterViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
{
}
#property(nonatomic,strong)IBOutlet UITableView *menuTable;
#property (nonatomic, weak) id<CellSelectionDelegate> cellDelegate;
#end
in your MasterViewController.m
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.cellDelegate respondsToSelector:#selector(rowSelected:)])
{
//sending selected indexPath, you can use indexPath.row in your detail view
[self.cellDelegate rowSelected:indexPath];
}
}
Now in your DetailedViewController.h
#import "MasterViewController.h"
#interface DetailedViewController : UIViewController<CellSelectionDelegate>
{
}
#property(nonatomic,strong)MasterViewController *masterView;
#end
in DetailedViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
//Set master page as the delegate.
masterView.delegate = self;
}
Now declare following delegate method
-(void)rowSelected:(NSIndexPath *)indexPath
{
NSLog(#"Your selected Row : %d",indexPath.row);
//do your work according to selection made in master view. use indexpath.row to identify which option was selected, you can also pass the other data with rowselected: method
}

UITableViewCells not displaying on screen after intercepting calls to UITableViewDelegate methods

While playing around with the iOS 7.1 SDK (on XCode 5.1.1), I am trying to intercept the calls to the delegate methods of UITableViewController by creating a class that implements the UITableViewDelegate and UITableViewDataSource protocol. I am expecting the tableView to delegate the calls to MyTableViewDelegate which does some customization and delegate back to HomeViewController.
Through debugging, I found tableView:cellForRowAtIndexPath: method and tableView:willDisplayCell:forRowAtIndexPath: of the HomeViewController, the drawRect: method of my custom UITableViewCell class was called, and the cells have right content. **So it seems to me that the cells are drawn to somewhere. But just not displaying on the screen (The table row divider lines were displayed on the screen though).**I wonder if anyone knows why it doesn't work. Below is the code snippet. Thanks in advance for your insights.
HomeViewController.h
// HomeViewController.h
#interface HomeViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
UITableViewController *tableViewController;
UITableView *tableView;
}
#property(nonatomic, strong) MyTableViewDelegate *myDelegate;
#end
HomeViewController.m
// HomeViewController.m
- (void)loadView {
[super loadView];
tableViewController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
[self addChildViewController:tableViewController];
[tableViewController didMoveToParentViewController:self];
myDelegate = [[MyTableViewDelegate alloc] init];
[myDelegate setDelegate:self];
tableView = [[tableViewController tableView] retain];
[tableView setFrame:[[self view] bounds]];
[tableView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
[tableView setDelegate:myDelegate];
[tableView setDataSource:myDelegate];
[tableView setClipsToBounds:NO];
[[self view] addSubview:tableView];
}
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyEntry *entry = [self entryAtIndexPath:indexPath];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellClass"];
if (cell == nil) cell = [[[cellClass alloc] initWithReuseIdentifier:#"cellClass"] autorelease];
[self configureCell:cell forEntry:entry];
return cell;
}
MyTableViewDelegate.h
// MyTableViewDelegate.h
#interface MyTableViewDelegate : NSObject <UITableViewDelegate, UITableViewDataSource> {
}
#property (nonatomic, assign) id delegate;
#end
MyTableViewDelegate.m
// MyTableViewDelegate.m
#implementation MyTableViewDelegate
#synthesize delegate;
// Display customization
#pragma mark - Delegate
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([delegate respondsToSelector:#selector(tableView:willDisplayCell:forRowAtIndexPath:)]) {
<...some customization ....>
[delegate tableView:tableView willDisplayCell:cell forRowAtIndexPath:indexPath];
}
}
...
// and all other required and optional methods declared by the UITableViewDelegate and UITableViewDataSource protocol.
EDITED:
if I set the delegate and dataSource of tableView to the HomeViewController instance rather than MyTableViewDelegate instance, it works just fine.
// HomeViewController.m
- (void)loadView {
[super loadView];
...
[tableView setDelegate:self];
[tableView setDataSource:self];
...
EDITED:
Normally we can just do all the work in HomeViewController. However, in my case, I am trying to see if it's possible to insert a layer between HomeViewController and tableView. I have a special use case where I would expect HomeViewController to not be able to override the customization implemented in MyTableViewDelegate (intended to be a library). Hence, it's not a good idea to implement MyTableViewDelegate as a base class and make HomeViewController derive from it.
As far as I can see, the only connection between the HomeViewController and tableView is that tableView is managed as a subView by HomeViewController and tableViewController is also a childViewController of HomeViewController. Would the additional layer (ie. MyTableViewDelegate) break this connection since MyTableViewDelegate delegates every method call back to HomeViewController? If so, how does it break? Again, without the MyTableViewDelegate layer, the above code works just fine.

UITableView's custom delegate doesn't get called when displayed from UIPopoverController

Hoping someone had to solve related issues .. this is driving me nuts :/
My UITableViewController implements a custom delegate method:
.h
#protocol folderDelegate
#required
- (void)folderViewDidSelectPlan:(NSString*)planId;
#end
#interface FolderViewController : UITableViewController
#property (nonatomic, assign) id delegate;
#end
.m
#implementation FolderViewController
#synthesize delegate;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
NSDictionary *row = [self->resultsPlan objectAtIndex:indexPath.row];
if ([delegate respondsToSelector:#selector(folderViewDidSelectPlan:)]) {
[delegate folderViewDidSelectPlan:[row objectForKey:#"id"]];
}
}
In my iPad's MainView I'm displaying this UITableView via UIPopoverController:
#interface ProjectViewController ()<folderDelegate>
...
- (void) selectPlan:(UIBarButtonItem*)sender
{
if([self->popoverSelectPlanController isPopoverVisible]){
[self->popoverSelectPlanController dismissPopoverAnimated:YES];
}
FolderViewController *folder = [[FolderViewController alloc] initWithStyle:UITableViewStyleGrouped withInstallation:self->_installationId withProjectId:self->_projectId withParentFolderId:#""];
folder.delegate = self;
UINavigationController *folderNavView = [[UINavigationController alloc] initWithRootViewController:folder];
self->popoverSelectPlanController = [[UIPopoverController alloc] initWithContentViewController:folderNavView];
[self->popoverSelectPlanController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
And handling the delegate via:
- (void) folderViewDidSelectPlan:(NSString *)planId
{
NSLog(#"called");
}
However, folderViewDidSelectPlan never get's called - I'm really stuck here, hope anyone has an idea how to solve this.
Thanks a lot!
Try to change declaration of the property to:
#property (assign) id<folderDelegate> delegate;
And also use self.delegate instead of in your UITableViewController.m file every time instead of just delegate.
If you don't have to support iOS4 or less remove synthesise from UITableViewController.m.

How to Enable UI botton in ViewController A upon on row selection in TableViewController B

I have two view controllers (Both Embedded in Navigation Controllers) in tab bar controller. ViewControllerA is has two buttons (MybuttonA and MybuttonB with enabled box unchecked in storyboard). ViewControllerB is a TableViewController. I would like to enable a buttons in ViewControllerA upon selecting specific rows in ViewControllerB table. Each button is expected to push different view controllers when enabled.
My present code works only when ViewControllersA and ViewControllersB are not embedded in Navigation Controllers. But without Navigation controller embedding, the enabled buttons does not push ViewControllers.
ViewControllerA.h
#import <UIKit/UIKit.h>
#interface ViewControllerA : UIViewController {
IBOutlet UIButton * MybuttonA;
IBOutlet UIButton * MybuttonB;
}
-(IBAction)mybuttonaction:(id)sender;
#property(strong,nonatomic)UIButton *MybuttonA;
#property(strong,nonatomic)UIButton *MybuttonB;
#end
ViewControllerA.m
#import "ViewControllerA.h"
#interface ViewControllerA ()
#end
#implementation ViewControllerA
#synthesize MybuttonA;
#synthesize MybuttonB;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(IBAction)mybuttonaction:(id)sender{
//write code to push view controller
}
ViewControllerB.h
#import <UIKit/UIKit.h>
#import "ViewControllerA.h"
#interface ViewControllerB : UITableViewController{
ViewControllerA *viewcontrollerA;
}
#property (nonatomic, retain) ViewControllerA *viewcontrollerA;
#end
ViewControllerB.m
#import "ViewControllerB.h"
#import "ViewControllerA.h"
#interface ViewControllerB () {
}
#end
#implementation ViewControllerB
#synthesize viewcontrollerA;
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"CONTENTS";
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(reload) forControlEvents:UIControlEventValueChanged];
[self reload];
[self.refreshControl beginRefreshing];
viewcontrollerA = [self.tabBarController.viewControllers objectAtIndex:0];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{return 1;}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
{return 5;}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat: #"Cell #%d", indexPath.row];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSString* value = [tableView cellForRowAtIndexPath:indexPath].textLabel.text;
if ([value isEqual:#"1"]){
viewcontrollerA.MybuttonA.enabled=YES;
}
else if ([value isEqual:#"2"])
{
viewcontrollerA.MybuttonB.enabled=YES;
}
}
else {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
}
#end
Use this:
viewcontrollerA = ((UINavigationController*)[self.tabBarController.viewControllers objectAtIndex:0] ).topViewController
Instead of this:
viewcontrollerA = [self.tabBarController.viewControllers objectAtIndex:0];
Use Delegation or 'NSNotification' to pass messages in between objects. Create a protocol for class B and send a message to its delegate when selecting particular row in it and make view controller A conform to this protocol. Make changes in view controller A when it receives the delegate message from view controller B.
Or for a loose broadcasting, you can fire/post a notification on row selection in view controller B and make view controller A a listener to it and change views on the posting of notification.
Although Delegation is the way to go in your case.

how to pass data from tableview to another tableview cell?

I am using static UITableView to show profile of a customer.
It has SelectCountryCell to select country which, when clicked, opens new UITableView with country list.
When I select country from Country TableView, It should display in previous TableView's SelectCountryCell.
How do I do this?
You should bind the static cells to outlets in your UITableViewController and put the profile syncing methods to the - viewWillAppear method.
When the user changes the country in the Country list the profile updates. After that when the user moves back to the UITableViewController instance with static content the profile data will be automatically updated.
You can define a delegate in your CityTableView and then define a method in this delegate.
You should realize this method in your CountryTableView.
Then you may get what you want.
I only offer you a thought. You should find the detail by yourself.
MasterViewController.h
#import "DetailViewController.h"
#interface MasterViewController : UITableViewController <DetailProtocol> // Note this.
#property (strong, nonatomic) DetailViewController *detailViewController;
#property (strong, nonatomic, readwrite) NSString *selectedCountry;
#end
MasterViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.detailViewController) {
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
}
self.detailViewController.delegate = self; // THIS IS IMPORTANT...
[self.navigationController pushViewController:self.detailViewController animated:YES];
}
// Note this -- It's a delegate method implementation
- (void)setCountry:(NSString *)country
{
self.selectedCountry = country;
}
DetailViewController.h
#protocol DetailProtocol <NSObject>
-(void)setCountry:(NSString *)country;
#end
#interface DetailViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (unsafe_unretained) id <DetailProtocol> delegate; // Note this
#end
DetailViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[self.delegate setCountry:[countries objectAtIndex:indexPath.row]]; // Note this
[self.navigationController popViewControllerAnimated:YES];
}

Resources