- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == sessionListTable){
selectedSessionId = [[self.sessionNames objectAtIndex:indexPath.row] objectForKey:#"session_id"];
selectedSessionName = [[self.sessionNames objectAtIndex:indexPath.row] objectForKey:#"session_name"];
NSLog(#"%#",selectedSessionId);
[StudentCommon sharedInstance].mTeacherSessionId = selectedSessionId;
[self remoteSessionButtonClick];
currentIndexPath = indexPath;
previousIndexPath = currentIndexPath;
[sessionListTable reloadData];
[sessionListPopUp removeFromSuperview];
}
TheUILabel` inside table view is not responding to touch, though the touch is working only in Empty space of the cell.
Verified all the connections, constraints and classes.
Check all the properties of inside UI elements in Attribute Inspector,
make sure for all of them are user interaction is “Ticked” ☑️
Check the properties inside User Defined Runtime Attributes and remove which are
not required.
Check the Class name whether it’s the correct “Super Class” / “Relevant Custom
Class” or not.
Check inside Connections Inspector whether the connection is having any warning ⚠️, if warning exists remove connection and connect again.
This is the image showing the User Defined Runtime Attributes, which was causing this error
First you should know that UILabel doesn't respond to TouchUpInside event.
Apart from that, the events those are raised in UITableViewCell, is not catchable in superview (i.e UITableViewController or UIViewController that is hosting respective table).
In order to achieve your goal, you need to change your UILabel to a UIButton. And in order to escalate TouchUpInside event to super view, you have two options:
1- Create a delegate for your cell, and utilise it in your superview.
2- Post a notification from your cell, and observe (catch) it in super view.
Good Luck. :-)
Related
What I'm doing?
I'm adding dynamic views to my UITableViewCell (which isn't subclassed).
Cell Hierarchy :
UITableView > UITableViewCell > cell.contentView > MainView > ([Number Of PointView] + [Options View]).
Here it is:
When a user will tap "Add Another Point", I'll add a PointView (which will be same as above) :
Y position [ ] X position [ ]
which will be look like this,
What is my logic to get this done?
I'm taking MainView from cell.contentView.
Then fetch last two views (Point View & Options View) added into MainView.
Add Another PointView in MainView.
Update frames for newly added PointView based on last PointView and also update frame of OptionsView.
Resizing height of MainView
And reloading particular cell.
I'm able to get it work, to confirm I've logged frame and subviews for that MainView. But once I tap on "Add Another Point" button again, I found that MainView isn't updated at all?
My simple question is, if I have a MainView (which I fetch from a Cell), can I update it directly or not?
P.S. I already have a poor solution for this is, to remove MainView and recreate new – which I found unnecessary. Any thoughts?
Short answer, yes you can.
cell.contentView is a placeholder. What you are likely running into is an entirely different problem: UITableViewCells are cached, then recycled and reused by the system.
Anytime you respond to cellForRowAtIndexPath, you basically need to reset the content.
I think what you should do. Just make this one cell class
This one other cell subclass
Use this method to insert your rows and also update your data source for table view that is the number of rows in section part
Your + button on click method can be like this..
//Use your own logic what you want to do.
Update your data source
NSIndexPath* index=[NSIndexPath indexPathForRow:[table count]-1 inSection:0];
NSMutableArray* indexPathArray=[[NSMutableArray alloc]init];
[indexPathArray addObject:index];
//index will be your new added point cell. Updating your datasource
[_myTableView insertRowsAtIndexPaths:indexPathArray
withRowAnimation:UITableViewRowAnimationTop];
Make this YES
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you want the specified item to be editable.
return YES;
}
I have UITableView which cells contain one UITextField in it. My UITableViewController is a delegate of all this text fields. Now, when UITableViewController gets deallocated, I want to set delegate of all that text fields to nil. The text field has a tag, so I can get it by it's tag once I have a cell.
The question is how to get all created cells? Asking UITableView for visibleCells returns only visible cells, but it can happen, that there is a row which is not visible, bit it still has my UIViewController as a delegate. So I really need to get all created cells somehow. cellForRowAtIndexPath does the same, so it wouldn't work for me either. The only way I see here is to store all text fields in array, but may be there is a better way?
Here is some code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:#"reuseId"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"reuseId"];
UITextField *nameTextField = [[UITextField alloc] initWithFrame:nameTextFieldRect];
nameTextField.tag = TEXT_FIELD_TAG;
nameTextField.delegate = self;
[cell.contentView addSubview:nameTextField];
}
return cell;
}
-(void)dealloc
{
// todo: get all text fields and set theirs delegate to nil
}
Well, most answers suggest that I don't need to set delegate to nil, but as I'm paranoid, I suspect that the following scenario is possible:
User taps 'Back' button, so dealloc of my view controller is called. In dealloc my view controller releases it's table view, but the tableView still exists at this point, as well as all the text fields. And if somehow one of text fields would call it's delegate method at this point, the app would crash, because the delegate is not a valid object anymore.
If someone can explain why this scenario is not possible, than it would convince me that I don't need to set delegate to nil.
You do not need to do that. All of the cells will be deallocated as well, so they won't have a reference to the delegate.
By default the delegate is a weak reference, so it will not retain your object.
I am not expecting to have this answer marked as accepted, but this won't fit into a comment window.
So, rather than us trying to convince you, you could start one of the most important tool for an iOS developer, which is the profiler. And see for yourself by playing with the interface that you should get no more than the number of cells necessary to fill the screen are kept allocated, and then when you tap back, all are getting deallocated.
If they are not, they probably have a strong reference to something else, but this can easily detected with the profiler.
I also like to add that when working with cells the act of scrolling UITable, tap back enter again into table, scroll tap back (repeated at least 10 times) it's a mandatory practice to detect memory leak.
Also, I don't know the purpose of assigning a tag to the cell, I maybe wrong but with this:
nameTextField.tag = TEXT_FIELD_TAG;
consider that you have more than one cell with the same tag, therefore you cannot simply recall the desired one. I remember that the rule is the first placed on screen 'win' the TAG (or kind of).
[UPDATE]
Just a guess, I have never proved this, but to stay on the question, if your problem is to have a cell first for having the UITextView, have you tried to loop the main view and just ignore the cell:
UITextView textView = [mainView viewWithTag:TEXT_FIELD_TAG];
while(textView!=nil){ // or whatever loop or criteria you like
// deallo, nil, etc...
textView = [mainView viewWithTag: TEXT_FIELD_TAG];
}
Create a new delegate/protocol for that cell, and implement that delegate in the view controller, like PersonTableViewCellDelegate. Apart from that, your cell implements the UITextField delegate and in that code, call [self.delegate onKeyPressed] or whatever. I recommend you pass also a reference of the cell, so in the view controller you can use indexPathFromCell (or something like that) to know the position of the cell. If you are interested tell me about it and will copy some code.
I am new to iOS programming. My cell is in a .nib. This cell displays an image which is working fine. I don't want the cell to perform any action or be selected. So, I have the following code :
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.userInteractionEnabled = YES;
My problem is I have a button which isn't called on touch. I have an action defined in the cell.m file. But nothing happens. I also tried adding the button programmatically, but in vain. I will appreciate any help or pointers as I have tried this for past few hours. I am pretty sure I am doing something silly.
Update:
This is how my cell xib structure looks -
There cell.nib, cell.m and cell.h. There is MainViewController which uses dequeueReusableCellWithIdentifier method to get the cell. This works fine as I am able to see the cell with the correct image. Action method is defined inside cell.m
Here is the xib file
https://www.dropbox.com/s/mzqzi6iz8lkbx2f/SHTableCell.xib
Thanks.
After checking the SHTableCell.xib you shared, it seems you have prevented user interaction on the cell itself so enabling user interaction on it's contentView / subViews will not make a difference.
In your xib, select "Test Cell" and check "User Interaction Enabled"
Also, it seems you haven't specified a re-use identifier to the cell.
It would be better if you specified one so that your -cellForRowAtIndexPath: could properly re-use the cell.
So... if you have something like:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
SHTableCell *cell = (SHTableCell*)[tableView dequeueReusableCellWithIdentifier:#"SomeIdentifier"];
//...
}
then, "SomeIdentifier" is what should be in the xib in the first place.
I have a UITableViewController with prototype cells containing UITextFields. To configure these custome cells, I've created a UITableViewCell subclass. I've conected the textField to the cell subclass via an outlet (nonatomic, weak).
On this subclass I've created a protocol for which the UITableViewController is its delegate so that everytime something changes in these textFields, the TableViewController knows about it. Basically I wanted this to save the values on the NSUserDefaults
Besides, in order to dynamically obtain values from these textFields, I can do something like this:
((TextFieldCell*)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]]).textField.text
It works ok most of the times. However when the textField is outside of the view because it has scrolled, the vaulue I get from textField.text is (null). As soon as it gets in the view again, everything goes back to normal.
I tried to change the outlet from weak to strong but to no avail.
I guess I could define some private NSStrings on the class, and fill them out when the delegate protocol gets called. The thing is that I wanted to get my code as generic as possible, keeping the need for private variables as low as possible, mostly to simplify the cell generation code.
Is there any other way to get the values of the textFields when they are outside of the view?
Thanks in advance!
But you know that UITableView only keeps Cells for the visible rect?
When a cell leaves the screen, and a new cell is needed for another cell moving into the visible area, the old cell is reused for the new content.
So there is not one cell for each row of your table view.
And if your table contains a lot data, there are far more rows than cells.
As Thyraz said, the UITableView only keeps cells for the visible rect -- and a reasonable buffer to allow for scrolling. Thats why 'reuse identifiers' are so very important, they indicate which cells can be used for which tables (critical when you have more than one table to worry about). Unfortunately, that doesn't answer your question by itself.
The responsibility for storing the contents of those textViews isn't on the UITableView's shoulders. It's your job to provide that data through the data source delegate protocols, and therefore you should be querying the data source for that information.
Edit: Which means that yes, you should be storing this data somewhere else, usually in the form of properties on the view controller class that contains the table view. I'd recommend the use of NSArray for the purpose, but you can also do it through dicts or even, at the last resort (and this is more a in theory you can do this, but it's an incredibly bad idea kind of thing), a series of properties. Personally, I almost always use NSArrays because they're structured in a manner appropriate to the problem, but you could theoretically do it other ways. (I've used a dict based structure exactly once, and that was a situation where my data was nested inside itself in a recursive structure)
UITableViewController doesn't keep cells around once off the screen. You can use the following pattern to get a previously used one as a memory management optimization, but you MUST assume that cells need to have the values reset on them every time they come onto the screen (even if dequeued) because there is no guarantee what the values will be.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if( cell == nil ) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier1] autorelease];
cell2.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell2.editingAccessoryType = UITableViewCellAccessoryNone;
}
switch( indexPath.section ) {
case first_Section:
if( row == 0 ) {
cell1.textLabel.text = #"Some Text";
cell1.accessoryView = [self myCustomViewControl];
cell = cell1;
}
... etc
}
}
I have two labels with two seperate tags each one.
I would like to detect which one label was pressed by checking the tag.
Inside the
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {}
i can retrieve one of them by code like this:
cell = [walltable cellForRowAtIndexPath:indexPath];
topLabel= (UILabel *)[cell.contentView.subviews objectAtIndex:0];
but i do not know the one that was pressed.
Is there a way to achieve to find which one label was pressed by the user?
Something important I want to point out: your reference to the label:
topLabel= (UILabel *)[cell.contentView.subviews objectAtIndex:0];
is not the correct, generic way to do this. I would recommend attaching the elements in your cell to an IBOutlet, and get the reference from there.
As for your question about UILabel touch events, I think a good way to achieve this is to add a UITapGestureRecognizer to your label, like so:
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(firstLabelTapped)];
[firstLabel addGestureRecognizer:tgr];
[tgr release];
Do the same with the second label. If you want to pass back information to the TableView's view controller, do this with delegation. Good luck!
You can use touch events and label's tag as suggested in this question and answer.
Handling Touch Event in UILabel and hooking it up to an IBAction
One method, as suggested above, is to assign a tag to each label, then evaluate the tag of the calling UILabel in your callback.
Another approach if you're using a custom cell (i.e., a subclassed UITableViewCell, versus a standard UITableViewCell to which you've added custom content/layout) is to simply define each of the two labels as properties of your subclassed cell. If the labels are assigned as respective properties, you can evaluate those properties against the caller and determine which label was pressed.