I added this code to my ViewController class under (#pragma mark - UITableViewDelegate Methods)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSLog(#"selected cell = %#", cell.textLabel.text);
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
NSLog(#"row = %ld", indexPath.row);
}
I just want to display the text that I select but it's not working. Any ideas what I'm doing wrong?
Full code is here: IOS 8 Objective-C Search bar and Table view Using Google Autocomplete
Thanks for the help!
EDIT:
I also added the following code:
viewDidLoad method (ViewController.m)
_tableView.allowsSelectionDuringEditing = YES;
_tableView.delegate = self;
_tableView.dataSource = self;
changed ViewController.h code from
#interface ViewController : UIViewController
to
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
in viewDidLoad set the delegates
_table.delegate = self;
_table.dataSource = self;
in the interface then declare the protocols
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
[tableView reloadRowsAtIndexPaths:]... only works when wrapped inbetween [tableView beginUpdates] and [tableView endUpdates];
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
check if the delegate is set to self
_tableView.delegate = self;
Use the debugger and break points.
I would put a break point in:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
and see if the program stops there or not.
Have you set this properties in Interface Builder?
Adding the method is not enough. You should set your 'delegate' property of table view to the 'self' where 'self' means your view controller.
For example in your .m file:
#interface MyViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
}
...
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
}
EDIT: Also please make sure you have connected the tableView property with a table view object inside of Interface Builder.
Method name changed or wrong. You can drag-drop to set the ViewController as the delegate. But this method needed to process when row touched:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("section: \(indexPath.section)")
print("row: \(indexPath.row)")
// caller is set to the calling ViewController, when it "prepare" to launch this one
caller.payFromSelection( selectedIndex: indexPath.row )
}
Back in the main controller, it gets the value and closes the child vc having the tableview...
func payFromSelection( selectedIndex:Int ) -> Void {
print( selectedIndex )
self.navigationController?.popViewController(animated: true)
//self.navigationController?.popToRootViewController(animated: true)
}
Related
I'm trying to hide a label in my TableViewCell when I go into "editing mode". So I created a protocol:
// UITableView Class
#protocol CellDelegate <NSObject>
- (void)toggleOpacityOff
- (void)toggleOpacityOn
#end
//in #interface
#property (nonatomic, strong) id <CellDelegate> delegate;
I implemented these methods in the UITableViewCell class and passed the delegate to the cell class:
// cellForRowAtIndexPath method
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
self.delegate = cell;
return cell;
But when I run this the methods apply only to the top most cell in the TableView.
Why is that and how can I fix it? Many thanks! :)
You should be able to fix this by changing the following line to set the correct delegate (remember that delegates should always be weak, not strong!):
self.delegate = cell;
to line:
cell.delegate = self;
The longer explanation is that delegate would not be the correct way to achieve this.
Delegates are meant to message back some specific action or information, this way your cell would actually tell the delegate that it had something togged on or off. This makes no sense, because you are looking to toggle something off.
The correct way of achieving your goal is to create a UITableViewCell subclass and implement those methods on a cell (toggleOpacityOff and toggleOpacityOn). Or even better create a specific cell property and override it's setter. Then you call this method in UITableViewDelegate method tableView:didSelectRowAtIndexPath:. See the following example:
#interface MyCell : UITableViewCell
#property (nonatomic) BOOL opacity;
#end
#implementation MyCell
- (void)setOpacity:(BOOL)opacity
{
if (opacity)
{
// Set opacity to ON
...
}
else
{
// Set opacity to OFF
}
}
#end
To loop through all cells:
- (void)updateCells
{
for (NSInteger i = 0; i < [self tableView:self.tableView numberOfRowsInSection:0]; i++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
MyCell *cell = (MyCell *)[self tableView:self.tableView cellForRowAtIndexPath:indexPath];
cell.opacity = YES;
}
}
In addition to this, it might be wise to remember this state in your model, so it remains correct when cells are reused (when scrolling).
Just keep some BOOL in your tableview class like isInEditMode. Then you add something like this into your cellForRowAtIndexPath
if (isInEditMode)
[cell.myText setHidden:YES];
else
[cell.myText setHidden:NO];
And once you want to switch into edit mode you just do this
self.isInEditMode = YES;
[self.tableview reloadData]
I try to search this problem in this site and I found this link How to insert items to a UITableView when a UIButton is clicked in iOS. But my problem is, I already copy the code on that link and It doesn't reload the data when I insert a value to my array.
here's the code "ViewController.m"
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic,strong) NSMutableArray * array;
#property(nonatomic,weak) IBOutlet UITableView * tableView;
#end
#implementation ViewController
-(NSMutableArray *) array{
if(_array==nil){
_array=[[NSMutableArray alloc] init];
}
return _array;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)addInfo:(UIBarButtonItem *)sender {
[self.array addObject:#"sample"];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"TodoListItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [self.array objectAtIndex:indexPath.row];
return cell;
}
#end
here's the code "ViewController.h"
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#end
Is there something wrong with my code or there is something that I need to setup to my tableview? I'm very confuse of this and try to figure out the missing part of my code. I'm still studying the code of object c and I'm still noob for this. Please help me and thanks in advance.
How did you insert the UITableView?, on nib or programatically?, either way you need to flag the table's delegate and datasource, if on nib, right click on table and see that delegate and data source are connected to the files owner, if programatically check
self.MyTable.datasource = self
self.MyTable.delegate = self
please see how to check if connected [dataSource and delegate should be with a dot, if not click on circle and drag line to file's owner for both]
table delegate and datasource on interface builder "NIB"
Also please note that on this image outlet is not connected, you have to connected also to call the reload as you are doing now
edit, check if the button is connected?, put a log or a break point on ibaction for your button to know if is called
edit 2, you have to init the array, are you calling it? do this in view will appear or when you want to use it
edit 3, try this
- (IBAction)addInfo:(UIBarButtonItem *)sender {
if(self.array==nil){
self.array=[NSMutableArray array];
}
[self.array addObject:#"sample"];
[self.tableView reloadData];
}
I have a segue from a view controller - with a enclosed tableview - to another view controller. I can segue from each cell in the first controller to the second with no problem. However, when I return to the first controller, the cell view is blank.
The dilemma is -- If I use this method:
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
the cell is visible but segues do not work.
Does anyone know of an alternative method?
Thanks
You need to create custom table view cell(may be you already have one, then tweak it), lets call it MyTableViewCell. Then add UITapGestureRecognizer to handle tap events on cell's contentView. When tap occurs you can execute custom block, which you should setup for cell. In block you can perform desired segue. But enough word, lets see some code!
First, lets define MyTableViewCell
MyTableViewCell.h
typedef void (^MyTableViewCellTapBlock) ();
#interface MyTableViewCell : UITableViewCell
#property (nonatomic, strong) MyTableViewCellTapBlock tapBlock;
#end
MyTableViewCell.m
#interface MyTableViewCell ()
#property (nonatomic, strong) UITapGestureRecognizer *tapRecognizer;
#end
#implementation MyTableViewCell
- (void)awakeFromNib {
self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[self.contentView addGestureRecognizer:self.tapRecognizer];
}
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"Tap logged");
if (self.tapBlock) {
self.tapBlock();
}
}
#end
Second, update your UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
__weak typeof(self) weakSelf = self;
cell.tapBlock = ^ {
[weakSelf performSegueWithIdentifier:#"showDetail" sender:weakSelf];
};
return cell;
}
Remarks
As you can see we have custom block that will be executed when user taps the cell. This block invokes performSegueWithIdentifier:, just do not forget to name your segue and change name in the sample.
Happy coding :)
Thanks for the efforts Keenie.. I will hold on to that code snippet and I know I'll use it.
This is embarrassing, but it turns out that all I needed to do, was on the return from the segue, to do [[self tableView] reloadData], and all was ok..
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.
I'm a newbie programming iOS and I've a problem adding a new cell to a UITableView object. I'm using an storyboard and one of the scenes is a UIViewController that has several subviews: textfields, a tableview, etc. I intend to add rows to this tableView from a detail scene.
I'm able to initially add rows to the table, but I'm not able to add a row afterwards. When I press a button to add the row I call the method '[self.stepsListTableView reloadData];' which produces a call to the method '- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section' and it returns a correct value, including the new array element. But method '- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath' is not called to update the table.
I do not understand what I'm doing wrong.
Details of my source code:
WorkoutDetailsViewController.h
(…)
#interface WorkoutDetailsViewController : UIViewController <StepDetailsViewControllerDelegate, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) id <WorkoutDetailsViewControllerDelegate> delegate;
#property (nonatomic, strong) Workout *workout;
(…)
#property (nonatomic, retain) IBOutlet UITableView *stepsListTableView;
(…)
WorkoutDetailsViewController.m
(…)
#synthesize stepsListTableView;
(…)
- (void)viewDidLoad
{
[super viewDidLoad];
addButton.enabled = FALSE;
workoutNameField.delegate = self;
if (self.workout == nil) {
self.workout = [[Workout alloc] init];
self.stepsListTableView = [[UITableView alloc] init];
}
self.stepsListTableView.delegate = self;
self.stepsListTableView.dataSource = self;
}
(…)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//return [self.workout.stepsList count];
NSInteger counter = 0;
counter = [self.workout.stepsList count];
return counter;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Set up the cell...
// Pending
return cell;
}
- (void)stepDetailsViewControllerDidDone:(StepDetailsViewController *)controller
{
[self.workout.stepsList addObject:controller.step];
NSInteger counter = [self.workout.stepsList count];
[self.stepsListTableView beginUpdates];
NSArray *paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:(counter-1) inSection:0]];
[self.stepsListTableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[self.stepsListTableView endUpdates];
[self.stepsListTableView reloadData];
}
(…)
Also in the storyboard, I have setup the outlets delegate and dataSource to be the controller view.
Any idea ?
Regards,
JoanBa
I have solved the issue. I have discovered using debugger that method reloadData was called for a different UITableView than the one initialized in viewDidLoad.
I reviewed the UITableView settings in storyboard, which aparently were correct but I have deleted them and created again. Now it works.
In UIViewController header I have the line
#property (nonatomic, retain) IBOutlet UITableView *stepsListTableView;
and in implementation I have commented lines
//self.stepsListTableView.delegate = self;
//self.stepsListTableView.dataSource = self;
And, of course, in storyboard I have defined for the UITableView the following relationships:
Outlets: dataSource, delegate --> UIViewController
Referencing outlet: UITableView --> UIVIewController
That's it !!
You may have the table view set to static content. Select the UITableView in Storyboard and in the "Attributes Inspector" section of the menu on the right of screen select the "Content" field under the "Table View" header and set the value to "Dynamic Prototypes".
Screenshot for clarity:
This little trick caught me out several times when I was starting out.