UITableView: How to get all rows for a particular section? - ios

What I want?
I want to add radio button functionality where a user in particular section can only select one row
How am I doing it?
I added UISwitch and based on what row user click I would like to do the following
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 1 || indexPath.section == 2) {
// disable all the rows of this section except indexPath.row
}
}
Where am I stuck?
How do I get all the rows for a given section in UITableView?
P.S: I am a week old to iOS and learning, so bear with me if this is a stupid question

Use[tableView cellForRowAtIndexPath:(NSIndexPath *)]
for (int i = 0; i < [self.tableView numberOfRowsInSection:indexPath.section]; i++) {
if (i != indexPath.row) {
UITableViewCell* cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:indexPath.section]];
//Do your stuff
}
}

Swift 3:
let rowsCount = self.tableView.numberOfRows(inSection: indexPath.section)
for i in 0..<rowsCount {
let cell = self.tableView.cellForRow(at: IndexPath(row: i, section: indexPath.section)) as! UITableViewCell
// your custom code (deselecting)
}
Thanks #Soul Clinic for help with this !

This should do the trick.
- (NSArray *)tableView:(UITableView *)tableView visibleCellsInSection:(NSInteger)section
{
NSPredicate *visibleCellsInSectionPredicate = [NSPredicate predicateWithBlock:^BOOL(UITableViewCell *visibleCell, NSDictionary *bindings) {
return [tableView indexPathForCell:visibleCell].section == section;
}];
return [tableView.visibleCells filteredArrayUsingPredicate:visibleCellsInSectionPredicate];
}
You can put it in a UITableView category if you want.

Related

Prompt on the last cell of the table view

I want UITableView always has the text "No more items" in the last cell, I want this row appears regardless of number of items, include 0 items. How could I do?
You can get the total row of a section by using numberOfRowsInSection: method.
NSInteger total = [self.tableView numberOfRowsInSection:indexPath.section];
// Check if last cell or no cell.
if(indexPath.row == totalRow -1 || indexPath.row == 0)
{
// Do your operation here
}
You can perform this in your cellForRowAtIndexPath or willDisplayCell methods. Hope it helps.
Just add the row regardless of your other items:
- (void)buildMenu {
[_menuItems removeAllObjects];
// ... add your items or not if you have 0
YourCellItem *lastItem = [[YourCellItem alloc] initWithTitle:#"No more items"];
[_menuItems addObject:lastItem];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _menuItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"yourCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
YourTableViewCell *basicCell = (YourTableViewCell *)cell;
YourCellItem *item = [_menuItems objectAtIndex:indexPath.row];
basicCell.itemTitle.text = item.title;
return cell;
}

UITableView won't present

I have a very strange situation in my app and i can't explain or locate the bug.
I have a UIViewController with a tableView in it.
In the table view I have 3 prototype cells, also i have 2 section that are divided like so:
first section: row 0 (cell ID: episodeScrollersCell)
second section: row 0 (cell ID: addCommentsCell)
: row 1+ (cell ID: commentCell)
The required methods in the protocol are listed below.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger rowNum;
if(section == 0){
rowNum = 1;
}else{
rowNum = 1; // here is the problem. If i change the number of row to above 1
}
return rowNum;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier;
if(indexPath.section == 0){
cellIdentifier = episodeScrollersCell;
}else if (indexPath.section == 1 && indexPath.row == 0){
cellIdentifier = addCommentsCell;
}else{
cellIdentifier = commentCell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
return cell;
}
Now the problem arises when I want to have 2 rows or above in the second section (i.e to have 2 prototype cells in one section), the view Controller won't show. I've logged the cellForRowAtIndexPath: method to see if the cells gets loaded and they do.
Any advice?
Thanks,
What you seem to be doing is trying to dequeue a reusable cell with a chance that no cell has been created before. However, if no cells have been created/allocated, then the dequeue will return a nil value. This tells the program that for the given indexPath there is NO cell to be displayed.
So, if you get a nil value from the dequeue function, your table will try to create a new cell with the given cell identifier. So, I would suggest you do something like the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier;
if(indexPath.section == 0){
cellIdentifier = episodeScrollersCell;
}else if (indexPath.section == 1 && indexPath.row == 0){
cellIdentifier = addCommentsCell;
}else{
cellIdentifier = commentCell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(!cell){
if(indexPath.section == 0){
//Initialise a new cell here, through a NIB or code
//For eg. cell = [[UITableViewCell alloc] initWithStyle: ...];
}
//Do the specific initialisation for each type of cell you need here
}
return cell;
}
This way, when the dequeue function returns a NIL value, your program automatically creates a new cell to fit in that place.
Hope this helps.

UITableView Cells With DIfferent Format & Behavior in Same Table Section

I have a UITableView with one section. All of the cells in that one section have cells that are derived from a subclass of UITableViewCell called PLContactCell.
What I'd like to do is, for the very last row of the table only, not use a PLContactCell. I just want to use a normal UITableViewCell that I can format however I would like. I'd also like to be able to have this cell NOT respond to being tapped.
My initial cellForRowAtIndexPath method is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PLContactCell *cell = [tableView dequeueReusableCellWithIdentifier:[PLContactCell reuseIdentifier]];
if (!cell) {
cell = [PLContactCell reusableCell];
cell.delegate = self;
}
id modelObject = [[sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([modelObject isKindOfClass:[NSString class]]) {
[cell configureWithString:modelObject];
} else {
[cell configureWithUser:modelObject];
}
return cell;
}
EDIT
So I tried created a UITableView cell in the XIB file and added the reuse identifier of "newCell" to it. Then I added this code:
if (indexPath.row == [[sections objectAtIndex:indexPath.section] count] - 1) {
NSString *CellIdentifier = #"newCell";
noFormatCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
This doesn't do anything. My question is, how do I access the last row of the section and how do I make it so that that cell it is not a PLContactCell but a UITableView Cell.
If it's always at the end, you might consider using the footer view of the UITableView. You can then keep some extra logic out of your UITableViewDataSource.
If it HAS to be as a cell, you'd have to add an extra row count on your last section, then do an if statement check to watch out for it in your -tableView:cellForRowAtIndexPath: implementation. I would strongly urge you try the footer approach, as it's cleaner and way easier to figure out what you were doing a few months/years from now.
Here's some code. Note you'd need to make another section if you are using grouped style in the UITableView.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == sections.count - 1) //Looking for last section
{
return [sections objectAtIndex:section].count + 1; //Add one to the last section
}
return [sections objectAtIndex:section].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = indexPath.row;
if ((sections.count == indexPath.section) && [sections objectAtIndex:indexPath.section].count == indexPath.row)
{
//Here you would create and return your UITableViewCell
}
PLContactCell *cell = [tableView dequeueReusableCellWithIdentifier:[PLContactCell reuseIdentifier]];
if (!cell) {
cell = [PLContactCell reusableCell];
cell.delegate = self;
}
id modelObject = [[sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
if ([modelObject isKindOfClass:[NSString class]]) {
[cell configureWithString:modelObject];
} else {
[cell configureWithUser:modelObject];
}
return cell;
}

Multiple cell types in section of UITableView

I am trying to aggregate data from three social networks (Facebook,LinkedIn,Twitter). I have all the appropriate and correct feeds and I also have difference cell types for them.
The question i want to ask is, how can i make a UITableView, containing 10 sections with 3 cells(plus three different cell types) per section in this order
Section 1:
[Facebook cell index 0 of the feed array]
[Twitter cell index 0 of the feed array]
[LinkedIn cell index 0 of the feed array]
Section 2:
[Facebook cell index 1 of the feed array]
[Twitter cell index 1 of the feed array]
[LinkedIn cell index 1 of the feed array]
Section 3:
etc etc etc
Play with the table view's data source & delegate. What's important is to use 3 different cell identifiers for 3 types of cells (unless you want them to have same look).
-numberOfSectionsInTableView: {
return 10;
}
–tableView:numberOfRowsInSection: {
return 3;
}
-tableView:cellForRowAtIndexPath:(NSIndexPath*)indexPath {
if (indexPath.row == 0) {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"FacebookCell"];
if (cell == nil) {
// Init FB cell here
}
// Load FB feed data into the cell here
return cell;
}
else if (indexPath.row == 1) {
// Twitter Cell, remember to user a different cell identifier
}
else ...
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 10;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellIdentifier = #"cellId";
customCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(indexPath.row == 0)
{
cell.textLabel.text = [FbFeed objectAtIndex:indexpath.section];
// set FacebookCell
cell
}
else if (indexPath.row == 1)
{
// set TwitterCell
cell.textLabel.text = [tweetFeed objectAtIndex:indexpath.section];
}
else if (indexPath.row ==2)
{
cell.textLabel.text = [linkedinFeed objectAtIndex:indexpath.section];
//set linkedin
}
return cell;
}
To build off the example, this can be used for any multiple type cells. You don't always have to use the row number to decide the type. You can get an object at the row and decide what type to show.
Also, if you are using storyboard, just add another prototype cell in the table, assign it a unique identifier, and set it up so you can use it. Works really well if you need different layouts that depend on the data returned.
-tableView:cellForRowAtIndexPath:(NSIndexPath*)indexPath {
//Check what cell type it is. In this example, its using the row as the factor. You could easily get the object and decide from an object what type to use.
if (indexPath.row == 0) {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"Type1Cell"];
return cell;
}
else if (indexPath.row == 1) {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"Type2Cell"];
return cell;
}
else {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"Type3Cell"];
return cell;
}
}

iPad: Iterate over every cell in a UITableView?

iPad: Iterate over every cell in a UITableView?
for (int section = 0; section < [tableView numberOfSections]; section++) {
for (int row = 0; row < [tableView numberOfRowsInSection:section]; row++) {
NSIndexPath* cellPath = [NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:cellPath];
//do stuff with 'cell'
}
}
To iterate over every visible cell in a UITableView:
for (UITableViewCell *cell in self.tableView.visibleCells) {
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell];
(edited to better state answer and hope that this is indexed more accurately for search results with the intention of saving others more time in the future)
(This builds on aroths answer.)
I like to define this as a category to UITableView so it's available everywhere.
(As mentioned a few times, you should be sure you really want to iterate over the cells themselves. For example: I use this to clear the UITableViewAccessoryCheckmark's from all the cells before setting it to the user selected cell. A good rule of thumb is to do this only if the datasource methods can't do what you need to.)
Define like this:
- (void)enumerateCellsUsingBlock:(void (^)(UITableViewCell *cell))cellBlock {
NSParameterAssert(cellBlock != nil);
for (int section = 0; section < [self numberOfSections]; section++) {
for (int row = 0; row < [self numberOfRowsInSection:section]; row++) {
NSIndexPath *cellPath = [NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell *cell = [self cellForRowAtIndexPath:cellPath];
if (cellBlock != nil) {
cellBlock(cell);
}
}
}
}
Call like this:
[self.tableView enumerateCellsUsingBlock:^(UITableViewCell *cell) {
NSLog(#"cell:%#", cell);
}];
It would be good style to typedef the block, too.
Swift 4:
for section in 0...self.tableView.numberOfSections - 1 {
for row in 0...self.tableView.numberOfRows(inSection: section) - 1 {
let cell = self.tableView.cellForRow(at: NSIndexPath(row: row, section: section) as IndexPath)
print("Section: \(section) Row: \(row)")
}
}
by steve
Iterate over all the UITableCells given a section id
Assuming a variable myTableView exists and its delegate and data source are both set:
UITableViewCell *cell;
NSIndexPath indexPath = [[NSIndexPath indexPathForRow:0 inSection:0];
for(indexPath.section = 0; indexPath.section < [myTableView numberOfSections]; ++indexPath.section)
{
for(indexPath.row = 0; indexPath.row < [myTableView numberOfRowsInSection:indexPath.section]; ++indexPath.row)
{
cell = [myTableView cellForRowAtIndexPath:indexPath];
// do something with this cell
}
}
Even simpler and more elegant:
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
// use the "cell" here
}
But obviously it doesn't fit all situations.
This how Im iterating over all table view cells even not visible ones , check my answer here :
https://stackoverflow.com/a/32626614/2715840
Hint : code in Swift.

Resources