UICollectionView, scrolling to an Item without knowing its NSIndexPath - ios

I have a UIcollectionview that shows an array of objects called Items.
At one point in the lifecycle of my app I do need to move the collectionview ( or scroll it ) to a specific Item that I receive Via NSnotification. I do not know the NSIndexPath of that Item but its definitely available in the collectionview.
I tried
NSIndexPath *myIndexPath = [NSIndexPath indexPathForItem:myItem inSection:1];
[self.collectionView scrollToItemAtIndexPath:myIndexPath
atScrollPosition:UICollectionViewScrollPositionCenteredVertically
animated:NO];
But this gives back an arbitrary number and not relevant.
How can I do that?

I dont know details of code so i am generalising my answer.
You can have a unique property for myItem say ID.
If you are maintaining an array of items say : myItemArray, and populating collection view in same order then following can work:
NSArray* myItemArray; //array used to populate collectionView
NSIndexPath *myIndexPath; //this is what we need to know
int index = 0;
//myItem is object of item type & notifiedItem is notified item
for (Item* myItem in myItemArray) {
if (myItem.ID == notifiedItem.ID) {
myIndexPath = [NSIndexPath indexPathForItem:index inSection:1];//you got the index path right
break;
}
index++;
}
//use the index path

Related

Can you downcast a NSIndexPath to NSInterger

I have a AVPlayer class that I'm using in a detail view that takes a indexPath of type Int.
I am getting the indexPath from the table view tableViewDidSelectAtIndexPath before sending it to the detail VC to use.
I tried to just simply downcast the NSIndexPath as! NSInteger before sending it to detail VC to use but it crashes without a crash message. So Im a bit stuck as to how to go about this.
Is it possible to downcast this? How can I get the number out of the NSIndexPath into an Int so I can use it in my class?
Objective C
NSInteger currentRow = indexPath.row;
Swift
let currentRow = self.tableView.indexPathForSelectedRow().row
NSIndexPath is always* a combination of section and either row (for UITableView) or item (for UICollectionView).
you need to dissolve the section by accessing the single index:
id object = [[self dataSource] objectAtIndex:[indexPath row]];
* EDIT
Respective the comments: you are right. Multiple indexes are possible with NSIndexPath.
If you know you have multiple indexes (what I wouldn't expect in UITableViewDelegate) you can iterate the indexes:
for (int i = 0; i < [indexPath length]; i++) {
NSUInteger index = [indexPath indexAtPosition:i];
// use index to access whatever you want
}
EDIT
PLEASE read documentation and headers before you ask the next time. Little hint: cmd-click NSIndexPath will take you to its header file with all possible informations.

iOS: reload single cell of UICollectionView

I am trying to follow the following post on reload a cell in a UICollectionView:
UICollectionView update a single cell
I know that I ultimately want something that looks like this:
[self.collectionView reloadItemsAtIndexPaths:??];
But I don't know how to find and pass the indexPath of a particular cell. Can anyone provide any pointers?
I have an NSMutableArray that contains all the cell information (imageViews that are generated in each cell). Ideally, what I'd like to do is pass the index of the NSMutableArray to refresh the corresponding cell on the page. But I'm not sure how the numerical index gets translated into an indexPath.
Thanks in advance for your help!
It depends on your implementation and how you have grouped your cells into sections but let's assume you have one section and each element in your array corresponds to a row in your table.
If you wanted to reload a cell corresponding to an array element at index x all you need to do is write
[_collectionView performBatchUpdates:^{
[_collectionView reloadItemsAtIndexPaths:#[[NSIndexPath x inSection:0]]];
} completion:^(BOOL finished) {}];
Conversely, if you have the cell but want to find its index path you can always call [collectionView indexPathForCell:myCell]
Toy have to pass an array containing the indexPaths that you want to be reloaded.
[self.collectionView reloadItemsAtIndexPaths: indexpathArray];
NSIndexPath has some property names section and row, both represents a cell. If your collection view has single section, you can create a NSIndexPath by setting its section = 0;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
Here rowIndex is your array index. Btw you have to make an array with you newly created indexpaths, then pass it to reloadItemsAtIndexPaths.
Hope this helps.. :)
Obj-C
NSMutableArray *indexPaths = [[NSMutableArray alloc] init]
[indexPaths addObject:indexPath];
[self.collectionView reloadItemsAtIndexPaths: indexPaths];
Swift 4.0
var indexPaths = [IndexPath]()
indexPaths.append(indexPath)
if let collectionView = collectionView {
collectionView.reloadItemsAtIndexPaths(indexPaths)
}
You can use this way for Swift 5.1:
collectionViewOutletName.reloadItems(at: [IndexPath(row: indexNumber, section: sectionNumber)] )
You can use this way for Swift 5:
CollectionView.reloadItems(at: IndexPath])
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dic = #{#"option":[NSNumber numberWithBool:YES]};
[self.array insertObject:dic atIndex:indexPath.row];
[collectionView reloadItemsAtIndexPaths:#[indexPath]];
}

Need to create an NSIndexPath for iCarousel to pass info to additional view controllers

I'm implementing an iCarousel that should pass information based on selection made to two additional view controllers.
To pass the information I understand that I need to create an NSIndexPath in the prepareForSegue method in the view controller that contains the iCarousel. The problem I'm having is creating an NSIndexPath since the carousel does not have rows.
In a tableview situation I could use the following:
NSIndexPath *path = [self.tableview indexPathForSelectedRow];
Can I simply change "tableview" to "carousel" and use something in place of indexPathForSelectedRow or is it more complicated than that?
As for creating the indexPath object:
You can create an indexPath with the
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:itemID inSection:0];
Giving a 0 value to the section index would not matter since, as you point out, there is no section in the carrousel
Finding the index for the itemID, if you use the nicklockwood's iCarousel :
int itemId = [self.myCarroussel currentItemIndex]

How to select row in uitableview programmatically based on NSString

I have a uitableview that hosts a number of cells, in another part of the app the user will make an NSString selection that will match on of the cells in the uitableview, how can I select hat cell programmatically?
I tried using the method
selectRowAtIndexPath:animated
but how can I get the indexpath? is there a better way?
I think you are loading data from an array. Then just search inside that NSArray and take index of the matched object. Now you can create NSIndexPath programatically:
[NSIndexPath indexPathForRow:index inSection:section];
Just use this NSIndexPath to select the row
try this .... first try to get the cell number based on string
NSString * pUserSelectedString = #"abcd";
int index;
if([array containsObject:pUserSelectedString])
{
index = [array indexOfObject:pUserSelectedString];
}
The way you needs to get the indexpath from source array is
int selectionIndex;
if([sourceArray containsObject:userSelectionString])
{
selectionIndex = [sourceArray indexOfObject:userSelectionString];
}
You have to check whether selection object is there or not before get the indexpath from sourceArray.then you have to use this indexpath for selectRowAtIndexpath:animated method

Dealing with UITableView's indexPathsForSelectedRows

I'm not sure how I can implement that my mock UITableView object answers correctly for indexPathsForSelectedRows.
In my App the user can (in editing state) select cells in a table view, which represents the files/folders of a given directory.
Once the user selects a folder item the previously selected files items should be deselected. My test (using OCHamcrest/OCMockito) looks like this.
- (void)test_tableViewwillSelectRowAtIndexPath_DeselectsPreviouslySelectedCells
{
// given
[given(self.mockTableView.editing) willReturnBool:YES];
// when
[self.sut tableView:self.mockTableView willSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:SectionIdFile]];
[self.sut tableView:self.mockTableView willSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:SectionIdFolder]];
// then
}
The problem is that I can verify that the file item is selected but I can't ask the the mockTableView for its selected rows. Could somebody tell me how to handle that? Do I have to record the tableView:selectRowAtIndexPath:animated:scrollPosition: calls myself and provide the correct answer when the tableView is asked for that information?
As the mockTableView can not record (like the real UITableView) the indexPath's of the selected cell, you have to make sure that the mock object returns the correct answer for that method. So in my case the test looks now like this.
- (void)test_tableViewwillSelectRowAtIndexPath_DeselectsPreviouslySelectedCellsForSectionIdFile
{
// given
[given(self.mockTableView.editing) willReturnBool:YES];
NSArray *selectedRows = #[[NSIndexPath indexPathForRow:0 inSection:SectionIdFile], [NSIndexPath indexPathForRow:1 inSection:SectionIdFile]];
[given([self.mockTableView indexPathsForSelectedRows]) willReturn:selectedRows];
// when
[self.sut tableView:self.sut.myTableView willSelectRowAtIndexPath:selectedRows[0]];
[self.sut tableView:self.sut.myTableView willSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:SectionIdFolder]];
// then
[verify(self.mockTableView) deselectRowAtIndexPath:selectedRows[0] animated:YES];
[verify(self.mockTableView) deselectRowAtIndexPath:selectedRows[1] animated:YES];
}

Resources