I have an array of dictionaries that populate a tableView as seen below
self.tableCell.usernameLabel.text = [self.loadTableArrayCopy[indexPath.row] valueForKeyPath:#"user.full_name"];
If the user likes the content of the row, they can press a save button on the cell and certain values from the dictionary are saved in Core Data.
The problem: not all values from the dictionary correspond to outlets in the uitableviewcell. If that were not the case, I could do something like this
savedItem.username = self.tableCell.usernameLabel.text
But since some values, such as thumbnails, are not displayed in the cell, I am not sure that I could do something like this since it's not associated with a cell
savedItem.thumbnail = self.thumbnail
My preferred option is to take the indexPath.row, access the dictionary at array[indexPath.row] and save by setting the managed object's properties from the dictionary. How can I get this dictionary out of the array and into a local variable so I can do something like this?
savedItem.thumbnail = [myLocalDictionary valueForKeyPath#"thumbnail"];
If you have single section, you can do it easily:
in cellForRowAtIndexPath set this:
cell.saveButton.tag = indexPath.row;
From save button event do this:
-(void)savePressed:(id)sender{
UIButton *btn = (UIButton *)sender;
int row = btn.tag; // This is your selected row.
NSDictionary *youDictionary = [array objectAtIndex:row];
}
When user tap save button then you could get the indexPath.row value.So later,
NSDictionary *saveDict = [array objectAtIndex:indexPath.row];
This way to will get dictionary and could further save it to coreData.
If not able to find indexPath.row value from button then you could do as below:-
-(void)buttonTapped:(id)sender
{
UIButton *senderBtn = (UIButton *)sender;
UITableViewCell *cell;
if (![Utilities isIPhone]) {
if ([UIDevice currentDevice].systemVersion.intValue < 7)
cell = (UITableViewCell *)[[[senderBtn superview] superview] superview];
else
cell = (UITableViewCell *)[[[[senderBtn superview] superview] superview] superview];
}
NSIndexPath *index = [advancedSearchTable indexPathForCell:cell];
}
When save is tapped you could add above lines and find out index(indexPath). Later, use index to get dictionary from array.
Related
I am trying to extract the values inputted to a textfield. The problem is these textfields are defined programmatically in a cell of a tableview.
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:(BOOL)animated];
NSUInteger numOfRows=[userControls count];
for (int i =0; i<numOfRows; i++) {
[self saveValueForRow:i];
}
}
#pragma save defaults
- (void)saveValueForRow :(int)index {
NSString *userDataString=userEntryField.text; //how to access each text field, as this currently just accesses the first one in the table
NSLog(userDataString);
[[NSUserDefaults standardUserDefaults] setObject:userDataString forKey:[controlKeys objectAtIndex:index]];
}
My instinct was to collect all the data after the view disappears. But I don't know how to access each different text field in each different cell.
You need to set the tag of cell in cellForRowAtIndexPath method as:
cell.tag = indexPath.row;
Now at the time of getting values of textField you need to first get the cell by indexPath like:
#pragma save defaults
- (void)saveValueForRow :(int)index {
NSIndexPath *nowIndex = [NSIndexPath indexPathForRow:index inSection:0]
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:nowIndex];
NSString *userDataString = cell.userEntryField.text; //how to access each text field, as this currently just accesses the first one in the table
NSLog(userDataString);
[[NSUserDefaults standardUserDefaults] setObject:userDataString forKey:[controlKeys objectAtIndex:index]];
}
Hope this Helps!
You can set a tag for each UITextField like:
//...
textview.tag = indexPath.row;
//...
So after you can access each textField by tag. I hope this can help you.
The feed of my app is managed by a UITableViewController where I set custom cells that are instances of a UITableViewCell sub class.
One property of that sub class is a UIButton called flameRelation:
#property (weak) IBOutlet UIButton* flameRelation;
I am creating a dynamic segue to a detail view controller depending on the class of the sender. If the sender is the cell itself, I pass a given set of data to my detail view controller. If the sender is the flameRelation button, I pass another.
To achieve this, I am looking at the following 2-step approach:
1) Since I need to know the indexpath.row of the cell where the FlameRelation button was pressed, I set the tag of that button in the UITableView method that sets each cell of my feed as follows:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Set a bunch of things before setting UIButton flameRelation tag
[cell.flameRelation setTag:indexPath.row];
And I am printing the tag which allows me to check that the tag is being set when I scroll down my feed after launching my build (I see the numbers incrementing as I scroll down, as expected).
NSLog(#"The button tag for this cell is set to %ld",(long)[cell.flameRelation tag]);
2) In the prepareForSegue method that allows the user to transition to the detail view controller with the relevant information, I test the class of the sender first. If the class of the sender is UIButton, I attempt to pass the right information to the detail view controller by setting the value of the indexpath to the value of the tag:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"FlameDetail"]) {
FlameDetailViewController* flameDetailController = (FlameDetailViewController*) segue.destinationViewController;
if ([sender isKindOfClass:[FlameCellTableViewCell class]])
{
NSIndexPath* indexPath = [self.tableView indexPathForCell:sender];
NSLog(#"The indexPath is: %#", indexPath);
flameDetailController.flame = [self.feed flameAtIndex:indexPath.row];
NSLog(#"class for object sender: %#", NSStringFromClass([sender class]));
}
else if ([sender isKindOfClass:[UIButton class]])
{
NSLog(#"The button tag is set to %ld",(long)[sender tag]);
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
NSLog(#"The indexPath from UIButton is: %#", indexPath);
flameDetailController.flame = [self.feed flameAtIndex:indexPath.row];
NSLog(#"The value of indexPath.row is %ld",(long)indexPath.row);
NSLog(#"class for object sender: %#", NSStringFromClass([sender class]));
flameDetailController.findOutView.hidden = NO;
[flameDetailController.flameAction setTitle:#"CHAT NOW" forState:UIControlStateNormal];
NSLog(#"Yes, the sender is UIButton");
NSLog(#"The title of flameAction is set to %#", flameDetailController.flameAction.titleLabel.text);
}
}
Everything works well if I tap on the cell itself, but if I tap on the flameRelation button, I see in my logs that the getter on tag returns 0. Which obviously doesn't transfer the proper information to my target view controller.
Thanks!
First of all why you are converting your tag value to indexPath and then getting your model data with the row number?
Your code:
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
flameDetailController.flame = [self.feed flameAtIndex:indexPath.row];
Try this instead:
flameDetailController.flame = [self.feed flameAtIndex:sender.tag];
I do not see a reason why this approach would not work. If it does not you need to share more code/details.
However, I would want to suggest another alternate (no so great though):
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
I am trying to execute an IBAction when a long-press is performed on a cell in a UITableView. The action involves the content of the cell so I need to get the indexPath in order to retrieve the content from a dictionary in local storage. The IBAction method is defined in the MasterViewController.m file which contains the UITableView methods and is subclassed from UITableViewController. I have tried all of the following, and they all return null instead of the indexPath for the cell.
UITableViewCell *cell = (UITableViewCell *)self;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
I have also seen a few years-old answers to similar questions that use the position of the cell in the view, but I can't get any of those to work either.
UPDATE:
The IBAction, sendToPB, is being defined in a subclass of UITableViewController. There is a long-press gesture recognizer added to the cell in Interface Builder, with Sent Actions connected to sendToPB. The action is supposed to be copying the content of the cell to the clipboard when you long-press on the cell in the table view. All the ways I have tried so far return null for indexPath.
- (IBAction)sendToPB:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSString *object = self.objects[indexPath.row];
UIPasteboard *pb = [UIPasteboard generalPasteboard];
NSString *pressedCellText = [[Data getAllNotes] objectForKey:object];
[pb setString: pressedCellText];
}
UPDATE:
I have found two problems with this approach. First, the long-press gesture doesn't actually select the row, which is why all of the options that used indexPathForSelectedRow don't work. Second, sender is the gesture recognizer, and not the cell or row, so using sender also produces a null value for indexPath. With these two factors in mind, how else can you detect which cell you performed the long-press on?
You can get indexPath Like This on longPressGesture!
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
CGPoint p = [gestureRecognizer locationInView:self.myTableView];
NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
if (indexPath == nil) {
NSLog(#"long press on table view but not on a row");
}
else if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"long press on table view at row %d", indexPath.row);
}
else
{
NSLog(#"gestureRecognizer.state = %d", gestureRecognizer.state);
}
}
may Be this Link will help you a little more
Declare variable 1st in .h file as
NSIndexPath *hitIndex;
then on long press method u can get the position of cell & hence indexpath
(void)longPressMethod:(UIButton *)btn
{
CGPoint hitPoint = [btn convertPoint:CGPointZero toView:tbl_traits];
hitIndex = [tbl_traits indexPathForRowAtPoint:hitPoint];
}
You can do it using Gesture Recognizers. Hope these snippets help.......
In your .h file
#interface yourClass ()
{
UILongPressGestureRecognizer *longPressRecognizer;
}
In viewDidLoad,
longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressDetected:)];
longPressRecognizer.minimumPressDuration = 2;
longPressRecognizer.numberOfTouchesRequired = 1;
longPressRecognizer.delegate = self;
In cellForRowAtIndexPath, just before return statement
[cell addGestureRecognizer:longPressRecognizer];
And at the end,
- (void) longPressDetected:(UILongPressGestureRecognizer *)recognizer
{
UITableViewCell *selectedCell = (UITableViewCell *)recognizer.view;
// Your required code here
}
Edit: Thanks to #RegularExpression
First be sure to set the delegate of your tableView
self.myTableView.delegate = self
I believe this is what you are looking for:
Swift
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//save the indexPath.row as an integer inside a property or pass it to your action
}
You can then save the index of from the above method or simple call your action passing that index inside the above method.
Objective-C
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//save the indexPath.row as an integer inside a property or pass it to your action
}
If this is inside a UITableViewController subclass, then casting self (which is an instance of the UITableViewController subclass) to UITableViewCell will not return the cell selected.
There is really 2 ways of doing this:
1- The easy way: Don't use an IBAction and just implement the delegate methods:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
2- The relatively easy way: in your IBaction, you can get the selected cell by using the property:
self.tableview.indexPathForSelectedRow
This property will give you the indexpath of the selected cell.
If you attached the UILongPressGestureRecognizer to the cell by calling cell.addGestureRegognizer(_: _: _:) you should retrieve the cell from the sender by doing
let touchedView = sender.view as! UITableViewCell
Anyway, the best way to achieve this usually is by inspecting the dataSource instead of calling the UITableViewDataSource methods
You could subclass UITableViewCell and add an IVar for the index path and set that when cellForRowAtIndexPath is called for the UITableView dataSource protocol.
i have a TableView with a Custom Cell and a Section Header. The Header shows me the Country and the custom Cell shows me the City.
which look like this:
USA
New York
Los Angeles
Germany
Berlin
Frakfurt
every Cell got a Button. after a press it will navigate and push the city name to the detail view .
The Problem is, that i don't know how to determine the city name after i pressed the button.
I had a solution but it doesn't work anymore:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
StandortCell *cell = (StandortCell *)[tableView dequeueReusableCellWithIdentifier:#"ortCell"];
[cell.detailButton setTag:indexPath.row];
cell.ortLabel.text = [managedObject valueForKey:#"stadtname"];
}
- (IBAction)detailButton:(id)sender {
UIView *contentView = [sender superview];
UITableViewCell *cell = (UITableViewCell *)[contentView superview];
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell];
NSInteger section = cellIndexPath.section;
UIButton * myButton = sender;
int row=myButton.tag;
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:row inSection:section];
StrasseViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"strasse"];
self.selectedStandort = [self.fetchedResultsController objectAtIndexPath:indexPath];
detail.currentStandort = self.selectedStandort;
[self.navigationController pushViewController:detail animated:YES];
}
when i use my old code it will just show the correct street row in the first section. it didn't detect the other sections(Countries);
When i choose the first city in the thirt section. it will display me the first city in the first section.
I hope you can help me.
use this I hope it will solve your purpose.
Create a button pressed method in your view controller
(IBAction)detailButton:(UIButton *)sender {
CustomUITableViewCellName *cell = (CustomUITableViewCellName *)[[sender superview]superview];
NSIndexPath *cellIndexPath = [YOUR_TABLE_NAME indexPathForCell:cell];
}
For ios 7 add another superview.
Now in this way you will get your IndexPath and you an get the current row by using
indexPath.row or indexPath.section.
You can get the title using sender.title property.
You can use this indexPath in your array to the required details.
You need to send row and section information seperately so make tag as
Tag= row*1000+section.
now from tag get section and row value using row= tag/1000
section =tag%1000
use this value to make correct index path or find some better then 2 mins solution to get that.
Caution its a workaround correct will be to
Subclass UIButton
Add a indexpath property int it
make your class to make button object and insted of tag set indexpath property.
in CustomButton.h
#interface CustomButton :UIButton
#property (nonatomic,assign)NSIndexPath *path;
#end
in CustomButton.m
#implementation CustomButton
#synthesize path;
#end
Use this custom button on your table view cell and instead of tag set path property
While moving from first view controller to second view controller I'm saving indexpaths in a array and in the return when loading a table in first view controller, if the current indexpath is in the saved indexpaths array I have to create a custom accessory button.
But, when scrolling UITableview along with the required cell another cell also getting custom button. When I'm printing the NSindexPaths while scrolling I'm getting random values instead of normal one's.
For the above I'm using the following code:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
// NSLog(#"newdata value is =%d",newData);
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
UITableViewCell *cell = [self.positionsTable dequeueReusableCellWithIdentifier:#"playersInPosition"];
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"playersInPosition"]autorelease];
}
UILabel *lblName = (UILabel *)[cell viewWithTag:100];
[lblName setText:[inputData objectAtIndex:[indexPath row]]];
UILabel *pname = (UILabel *)[cell viewWithTag:102];
[pname setText:[appDelegate.playersNFL objectAtIndex:[indexPath row]]];
for (NSIndexPath *object in appDelegate.indexPathList) {
if ([object isEqual:indexPath]) {
NSLog(#"saved index path values are =%#",appDelegate.savedIndexPath);
UIButton *button = [self ChangeAccessoryButtonStyle:appDelegate.indexPathList[0]];
cell.accessoryView = button;
}
}
return cell;
}
I don't remember any part of documentation saying the index-paths are meant to be reused by a table view, it might be a good idea then to compare the objects with a designed function:
compare:
Indicates the depth-first traversal order of the receiving
index path and another index path.
-(NSComparisonResult)compare:(NSIndexPath *)indexPath
Parameters
indexPath Index path to compare. This value must not be nil. If the
value is nil, the behavior is undefined.
Return Value
The depth-first
traversal ordering of the receiving index path and indexPath.
NSOrderedAscending: The receiving index path comes before indexPath.
NSOrderedDescending: The receiving index path comes after indexPath.
NSOrderedSame: The receiving index path and indexPath are the same
index path.
Availability
Available in iOS 2.0 and later.
Declared In
NSIndexPath.h
Try to remove this line and create cell each time.
UITableViewCell *cell = [self.positionsTable dequeueReusableCellWithIdentifier:#"playersInPosition"];