Indexpath of the button from UICollectionView - objective-c

I tried to:
- (IBAction)delete:(UIButton*)sender{
NSIndexPath *indexPath = [self.collectionView indexPathForCell:(TourGridCell *)[[[sender superview]superview]superview]];
}
But NSLog shows that cell exist, but indexpath is nil.

OK, here it is:
- (IBAction)delete:(UIButton *)sender{
NSIndexPath *indexPath = nil;
indexPath = [self.collectionView indexPathForItemAtPoint:[self.collectionView convertPoint:sender.center fromView:sender.superview]];
}

Sometimes it's the simplest possible answer. I was having exactly the same problem as #Schmidt, but was frustrated to see that his answer was to use indexPathForItemAtPoint:, as though indexPathForCell: was somehow broken and couldn't be used as intended.
Then I tried his solution, and still had the same result: the index path was coming back nil.
Solution: the view controller's collectionView outlet wasn't connected to the UICollectionView instance in the NIB (on the storyboard). After making that missing connection, both methods (indexPathForCell: and indexPathForItemAtPoint) worked as expected.
I know other devs run into this problem sometimes, so take this as a reminder: the problem may not be your code, per se, but rather something in Interface Builder like an unconnected outlet (or just as confusing, an outlet that's connected to something which no longer exists).

Swift version of the answer
var indexPath: IndexPath? = nil
indexPath = collectionView.indexPathForItem(at: collectionView.convert(sender.center, from: sender.superview))

Another best way is to subclass the UIButton and add an NSIndexPath property to it.
When loading the cell in
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath method
add this statement.
yourCell.customButton.indexPath = indexPath;
And
- (IBAction)delete:(UIButton *)sender
{
NSIndexPath *indexPath = sender.indexPath;
}

Related

Couldn't set values in Custom Cell in UITableView from NSMutableArray

Help me to get rid of with this dilemma that occurred yet when I tried to dequeued the cell (Custom Cell).Below are some steps and Indents that I did with my Project.
The very first is I drag and drop a UITableView in my ViewController and add the ViewController.h doing after this
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
Then I made a Custom Cell with 3 UILabels and change the height of the Cell to 65.
After that I made a property in ViewController.m
#property (nonatomic,strong) NSMutableArray *myTodoTitles;
Then in method(ViewDidLoad) I did.
myTodoTitles = [NSMutableArray arrayWithCapacity:10];
[myTodoTitles addObject:#"Go for ride"];
[myTodoTitles addObject:#"Do University Assignments"];
[myTodoTitles addObject:#"Watch Show"];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self.myTodoTitles count]-1 inSection:1];
[self tableView:self.myTodoTable cellForRowAtIndexPath:indexPath];
After that I just did these things in my ViewController.m
#pragma mark - Table view data source
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *myIdentifier = #"TodoCell";
TodoCell *todoCell = (TodoCell*)[tableView dequeueReusableCellWithIdentifier:myIdentifier];
todoCell.todoTitleLabel.text = [self.myTodoTitles objectAtIndex:indexPath.row];
return todoCell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [myTodoTitles count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
But when I run the project it dequeued nothing.
Please help
Most likely that you have not connected your viewController to be the dataSource of your tableView. This could be done from Interface Builder or from the code. You can easily check it by adding self.myTodoTable.dataSource = self; at the very first of viewDidLoad method.
And also: what did you mean by `
[self tableView:self.myTodoTable cellForRowAtIndexPath:indexPath];`
in viewDidLoad ? Seems like you wanted to do
[self.myTodoTable reloadData];
There are to UITableView methods with similar name:
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
and
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
forIndexPath:(NSIndexPath *)indexPath
The first one will try to dequeue a reusable cell. If it returns nil you are responsible to create appropriate cell.
The latter one will always return a valid cell: you will have to register a certain class or NIB with that tableview beforehand though. Docs.
EDIT:
As ReDetection pointed out: first method will also return a valid cell as long as you had registered a proper class (or nib) with that tableview.
In your case that means that you should register TodoCell in viewDidLoad with your tableView.
If TodoCell is made without .xib:
[self.tableView registerClass:[ToDoCell class]
forCellReuseIdentifier:#"TodoCell"];
Or if it is made with .xib.
[self.tableView registerNib:[UINib nibWithNibName:#"TodoCell"
bundle:nil]
forCellReuseIdentifier:#"TodoCell"];
EDIT2:
Your code also seems to be missing the dataSource setting. Something like:
self.tableView.dataSource = self;
This will trigger initial reload.
You'd probably want to set a delegate (since your controller claims to adopt that protocol) in the same manner.

AVAudioPlayer in cell, how to not release?

I've a collection view with custom cell class.
In each cell I've a player with a specific sound.
When made an Button and link to my code with an IBOutlet, it's doesn't fire even with the fact I have userInteractionEnabled = YES in all my views.
So I decided to play the sound in the collection view controller.
In my cell the player has a property
#property (strong, nonatomic) AVAudioPlayer *voicePlayer;
Then in the collection I have:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
LHFriendVoiceObject *currentFriendVoice = [[LHFriendVoiceObject alloc] initWithNSDictionnary:[self.friendsArray objectAtIndex:indexPath.row]];
[cell hydrateWithFriendVoiceObject:currentFriendVoice];
[cell.voicePlayer prepareToPlay];
//[self.voicesArray addObject:cell.voicePlayer]; tried to stock them in array but doesn't work
return cell;
}
If I play the sound in this method it's work, but I want the sound to be played when I select the cell.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
Here the sound doesn't play because voicePlayer is nil.
How I can keep my players ?
This code is the problem:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath {
LHFriendVoiceCollectionViewCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:#"LHFriendVoiceCollectionViewCell" forIndexPath:indexPath];
[cell.voicePlayer play];
}
That first line is wrong. You are calling dequeue. Big mistake! It makes a completely new cell. Do not make a new cell like that! Obviously that new cell will not have any AVAudioPlayer in it.
You already have a cell; it just got selected. Use the indexPath and cellForItemAtIndexPath: to learn out which cell got selected. That is the one you want to talk to.
PS You really should figure out why the button approach didn't work, but it's no big deal at this point.

call UITableView methods from UITouch

I have a table with customs cells, which has subclass UITableViewCells and for control touches I use UITouch (code based on this tutorial http://gregprice.co.uk/blog/?p=280) I need inside touchesEnded method get index of cell which was touch.
I try:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//some code
UITableView *parentTable = (UITableView *)self.superview;
NSIndexPath *index = [NSIndexPath alloc];
index = [parentTable indexPathForSelectedRow];
NSLog(#"Call, x= %f, index=%d", xPos, index.row);
}
But always I've got index=0.
Whats I do wrong?
it seems like you are taking a very round about way to select a row in a UITableView. set your UITableView's delegate and data source to the class you are working in, then implement its protocol methods which you can find in the UITableViewDelegate and UITableViewDataSource reference. Once you have done that you can use this method to determine which row was selected in the table
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
maybe you already knew this but it sounds like you are new to iOS development and i dont see why you would want to manually do it that way.
and also as Dave Leverton's answer said, dont do an alloc like that
Not sure this is causing the problems but it's bad practice to call 'alloc' like you are here. I'd remove the line with alloc (As this is creating memory for an object you're not initialising or using) and just have the NSIndexPath object defined in-line:
UITableView *parentTable = (UITableView *)self.superview;
NSIndexPath *index = [parentTable indexPathForSelectedRow];
NSLog(#"Call, x= %f, index=%d", xPos, index.row);

How to save state of UICollectionViewCell

Please help me, how can I save state of UICollectionViewCell. For example: I have cells with UIWebView and when I dequeueReusableCellWithReuseIdentifier:forIndexPath: returned wrong cell, not for this indexPath and after it UIWebView content will reloaded for correct indexPath with twitches. Thanks!
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NewsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"NEWS_CELL" forIndexPath:indexPath];
if (!cell.isShowed) { // I just added boolean property
cell.isShowed = YES;
/*** some init actions ***/
}
return cell;
}
If I use this method, cells with cell.isShowed == YES return on wrong indexPath. But if I not use cell.isShowed content of UIWebView will reloaded in every showing cell
Sorry for my english :)
See what Apple's UIWebView Class Reference say:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
But UICollectionView inherits from UIScrollView. So you need to redesign your architecture.

UITableView Center Cell Details

I am trying to sync a UITableView with a UILabel to make sure they show the same data; of course, things will be different in the end, but for testing this is what I need to do.
See the arrow? I want that middle cell (from px44-88) to show the cell.textLabel.text in a UILabel when it is the "middle cell".
I tried using - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath but I was having so many problems I figured I'd come here to ask if anyone has a better way of doing this. I'm not sure if it would make a difference or not but I am using NSFetchedResultsController to populate my UITableView.
UITableView is a subclass of UIScrollView, so probably you can use UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
member to detect which cell is currently in the middle.
I.e. assuming you have a plain table with no sections, and tableView is an outlet for the table, label is an outlet for the label, than this will function in your controller will work:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
int row = (scrollView.contentOffset.y + tableView.frame.size.height / 2) / 44;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
label.text = cell.textLabel.text;
}
Of course, you need to do some scrolling to make it work ;)
You can use visibleCells method to get layout of visible cells for non-plain table and use it to detect cell in the middle of the table.