Hangs when deleting large number of table view rows - ios

The following code will hang.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (_empty) {
return 0;
} else {
return 25000;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [tableView dequeueReusableCellWithIdentifier:#"Cell"];
}
- (IBAction)buttonPressed:(id)sender {
NSMutableArray *collector = [#[] mutableCopy];
for (NSInteger i = 0; i < 25000; i++) {
[collector addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
_empty = YES;
[self.tableView deleteRowsAtIndexPaths:[collector copy]
withRowAnimation:UITableViewRowAnimationNone];
}
I have filed a radar with apple for this (22865658).
Example project can be found here https://www.dropbox.com/s/upn9ee5svp11a1t/asdf.zip?dl=0

Related

How to create two custom tableview cell within single tableview using iOS Storyboard?

I am trying to create accordion tableview with seperate tableviewCell within single tableview using iOS storyboard. below I have added my test code. Please help me for solving issues.
My Source:
Tableview Methods Index data's I am getting from property list
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.itemsInTable count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *Title= [[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"Name"];
return [self createCellWithTitle:Title image:[[self.itemsInTable objectAtIndex:indexPath.row] valueForKey:#"Image name"] indexPath:indexPath];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dic=[self.itemsInTable objectAtIndex:indexPath.row];
if([dic valueForKey:#"SubItems"])
{
NSArray *arr=[dic valueForKey:#"SubItems"];
BOOL isTableExpanded=NO;
for(NSDictionary *subitems in arr )
{
NSInteger index=[self.itemsInTable indexOfObjectIdenticalTo:subitems];
isTableExpanded=(index>0 && index!=NSIntegerMax);
if(isTableExpanded) break;
}
if(isTableExpanded)
{
[self CollapseRows:arr];
}
else
{
NSUInteger count=indexPath.row+1;
NSMutableArray *arrCells=[NSMutableArray array];
for(NSDictionary *dInner in arr )
{
[arrCells addObject:[NSIndexPath indexPathForRow:count inSection:0]];
[self.itemsInTable insertObject:dInner atIndex:count++];
}
[self.main_tableview insertRowsAtIndexPaths:arrCells withRowAnimation:UITableViewRowAnimationNone];
}
}
}
CollapseRow Process
-(void)CollapseRows:(NSArray*)ar
{
for(NSDictionary *dInner in ar )
{
NSUInteger indexToRemove=[self.itemsInTable indexOfObjectIdenticalTo:dInner];
NSArray *arInner=[dInner valueForKey:#"SubItems"];
if(arInner && [arInner count]>0)
{
[self CollapseRows:arInner];
}
if([self.itemsInTable indexOfObjectIdenticalTo:dInner]!=NSNotFound)
{
[self.itemsInTable removeObjectIdenticalTo:dInner];
[self.main_tableview deleteRowsAtIndexPaths:[NSArray arrayWithObject:
[NSIndexPath indexPathForRow:indexToRemove inSection:0]
]
withRowAnimation:UITableViewRowAnimationNone];
}
}
}
Tableview UI. Same UI appearing Into child tableview cell also. I need to show seperate UI for parent and child tableview cell
- (UITableViewCell*)createCellWithTitle:(NSString *)title image:(UIImage *)image indexPath:(NSIndexPath*)indexPath
{
NSString *CellIdentifier_one = #"Cell_One";
cell_one = [self.main_tableview dequeueReusableCellWithIdentifier:CellIdentifier_one];
UIView *bgView = [[UIView alloc] init];
bgView.backgroundColor = [UIColor colorWithRed:54/255.0f green:169/255.0f blue:224/255.0f alpha:0.40f];
cell_one.backgroundColor = [UIColor colorWithRed:54/255.0f green:169/255.0f blue:224/255.0f alpha:0.25f];
cell_one.selectedBackgroundView = bgView;
cell_one.titlelbl.text = title;
cell_one.titlelbl.textColor = [UIColor blackColor];
return cell_one;
}
well you have indexPath. YOU must know which cell to use for which indexPath.
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id cell;
if(indexPath.row==0) {
cell = [self createCell];
}
else {
cell = [self createOtherCell];
}
return cell;
}

How to move row to another Section while clicking on row?

I have Implemented multi select row but what i have to do is when we click on row it will move on another section , Here's my code what i have tried is ?
can anyone help me out from this ? Thanks in advance ...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2; //assuming you have only two sections
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0)
return self.firstSectionDataSource.count;
else if (section == 1)
return self.dataArray.count;
else
return 0;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Here, Have to move row to another section while clcking ..
// other multiselect code
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Configure a cell to show the corresponding string from the array.
static NSString *kCellID = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
cell.textLabel.text = [self.dataArray objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
#try {
NSMutableArray *sourceArray = nil;
if (sourceIndexPath.section == 0) {
sourceArray = self.firstSectionDataSource;
}
else if (sourceIndexPath.section == 1)
{
sourceArray = self.dataArray;
}
NSMutableArray *destinationArray = nil;
if (destinationIndexPath.section == 0) {
destinationArray = self.firstSectionDataSource;
}
else if (destinationIndexPath.section == 1)
{
destinationArray = self.dataArray;
}
NSString *stringToMov = [sourceArray objectAtIndex:sourceIndexPath.row];
[sourceArray removeObject:stringToMov];
[destinationArray insertObject:stringToMov atIndex:destinationIndexPath.row];
}
#catch (NSException *exception) {
NSLog(#"exception = %# \n reason = %#",exception,exception.reason);
}
}
In cellForRowAtIndexPath
[cell setShowsReorderControl:YES];
And you need to implement the following UITableView delegate and data source methods properly
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2; //assuming you have only two sections
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0)
return firstSectionDataSource.count;
else if (section == 1)
return secondSectionDataSource.count;
else
return 0;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
#try {
NSMutableArray *sourceArray = nil;
if (sourceIndexPath.section == 0) {
sourceArray = firstSectionDataSource;
}
else if (sourceIndexPath.section == 1)
{
sourceArray = secondSectionDataSource;
}
NSMutableArray *destinationArray = nil;
if (destinationIndexPath.section == 0) {
destinationArray = firstSectionDataSource;
}
else if (destinationIndexPath.section == 1)
{
destinationArray = secondSectionDataSource;
}
NSString *stringToMov = [[sourceArray objectAtIndex:sourceIndexPath.row] retain];
[sourceArray removeObject:stringToMov];
[destinationArray insertObject:stringToMov atIndex:destinationIndexPath.row];
[stringToMov release];
}
#catch (NSException *exception) {
NSLog(#"exception = %# \n reason = %#",exception,exception.reason);
}
}
You can do the next:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView moveRowAtIndexPath:indexPath toIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
// other multiselect code
}
Try this -
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithObjects:[NSArray arrayWithObjects:[NSArray arrayWithObjects:#"a",#"b",#"c", nil],[NSArray arrayWithObjects:#"d",#"e",#"f", nil], nil] forKeys:[NSArray arrayWithObjects:#"firstSection",#"secondsection", nil]];
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[dict allKeys] count]; //assuming you have only two sections
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[dict objectForKey:[dict allKeys][section]] count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *arr = [dict objectForKey:[dict allKeys][indexPath.section]];
NSString *str = arr[indexPath.row];
if (indexPath.row!=0) {
[arr removeObject:str];
}
NSMutableArray *arr1 = [dict objectForKey:[dict allKeys][0]];
[arr1 addObject:str];
[tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *arr = [dict objectForKey:[dict allKeys][indexPath.section]];
NSString *str = arr[indexPath.row];
static NSString *kCellID = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
cell.textLabel.text = str;
return cell;
}

UISearchDisplayController display custom UITableViewCell when No Results

I have one UITableView consisting of some custom UITableViewCells and one UISearchDisplayController connected to it. How can I show another custom Table View Cell if there are no results when you search for something?
Here's how the search and table view functions look like:
- (void)searchTableList:(UISearchBar*)searchBar {
NSString *searchString = searchBar.text;
for (NSArray *section in _celebs)
for (NSDictionary *row in section) {
if ([[row[#"name"] lowercaseString] rangeOfString:[searchString lowercaseString]].location!=NSNotFound)
[filteredContentList addObject:row];
}
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
isSearching = YES;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[filteredContentList removeAllObjects];
if (searchText.length) {
isSearching = YES;
[self searchTableList:searchBar];
} else isSearching = NO;
}
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller{
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
isSearching = NO;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self searchTableList:searchBar];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [tableView isEqual:self.searchDisplayController.searchResultsTableView]?1:_objects.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tableView isEqual:self.searchDisplayController.searchResultsTableView]?filteredContentList.count:[_objects[section] count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return [tableView isEqual:self.searchDisplayController.searchResultsTableView]?0:25;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section {
return [self tableView:tableView heightForHeaderInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 55;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [self tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (NSDictionary *)getObjectFromIndexPath:(NSIndexPath*)indexPath tableView:(UITableView*)tableView {
BOOL search = [tableView isEqual:self.searchDisplayController.searchResultsTableView];
if (search)
return indexPath.row<filteredContentList.count?filteredContentList[indexPath.row]:nil;
else return indexPath.section<_objects.count?
(indexPath.row<[_objects[indexPath.section] count]?_objects[indexPath.section][indexPath.row]:nil)
:nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL search = [tableView isEqual:self.searchDisplayController.searchResultsTableView];
FirstTableViewCell *cell;
NoResultsTableViewCell *cell1;
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell = (FirstTableViewCell*)[self.tableView dequeueReusableCellWithIdentifier:#"FirstTableViewCell"];
} else {
cell = (FirstTableViewCell*)[self.tableView dequeueReusableCellWithIdentifier:#"FirstTableViewCell" forIndexPath:indexPath];
}
NSDictionary *object = [self getObjectFromIndexPath:indexPath tableView:tableView];
if (!object) return cell;
cell.object = celeb;
cell.objectName.text = [object objectForKey:#"name"];
}
}
return cell;
}
Make some changes like below:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]){
if (filteredContentList.count > 0){
return filteredContentList.count;
}else{
return 1; // the number of custom cells when there're no results
}
}else{
return [_objects[section] count];
}
}
- (NSDictionary *)getObjectFromIndexPath:(NSIndexPath*)indexPath tableView:(UITableView*)tableView {
BOOL search = [tableView isEqual:self.searchDisplayController.searchResultsTableView];
if (search)
return indexPath.row < filteredContentList.count? filteredContentList[indexPath.row]: theCustomCellDict; // use theCustomCellDict instead of nil
else return indexPath.section < _objects.count?
(indexPath.row < [_objects[indexPath.section] count]? _objects[indexPath.section][indexPath.row]: nil)
:nil;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL isSearch = [tableView isEqual:self.searchDisplayController.searchResultsTableView];
FirstTableViewCell *cell;
NoResultsTableViewCell *noReultsCell;
if ((isSearch && filteredContentList.count > 0) || !isSearch){
cell = (FirstTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:#"FirstTableViewCell" forIndexPath:indexPath];
NSDictionary *object = [self getObjectFromIndexPath:indexPath tableView:tableView];
if (!object) return cell;
cell.object = celeb;
cell.objectName.text = [object objectForKey:#"name"];
return cell;
}else{
noResultsCell = (NoResultsTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:#"NoResultsTableViewCell" forIndexPath:indexPath];
NSDictionary *object = [self getObjectFromIndexPath:indexPath tableView:tableView];
if (!object) return noResultsCell;
noResultsCell.object = celeb;
noResultsCell.objectName.text = [object objectForKey:#"name"];
return noResultsCell
}
}
If you want to just show information (for example there is no result found 'something' ) You don't need to use UITableViewCells. I will reccomend you to look DZNEmptyDataSet library.
GitHub link https://github.com/dzenbot/DZNEmptyDataSet

UITableView in Arabic is not working

I am having an issue with the header and the cellForRow in Arabic codes below.
The codes work in English.
Can anyone see what I am doing wrong and resolve the problem?
Thanks.
Unfortunately I am unable to post the image due to the 10 reputation things..
e.g from the UITableView
A
B
Abha
Abu Dhabi
C
Bahrain
Beirut
D
- (void)setupIndexData:objects {
self.collation = [UILocalizedIndexedCollation currentCollation];
NSInteger index, sectionTitleCount = [[self.collation sectionTitles] count];
NSMutableArray *newSectionArray = [[NSMutableArray alloc] initWithCapacity:sectionTitleCount];
for (index = 0; index < sectionTitleCount; index++) {
[newSectionArray addObject:[NSMutableArray array]];
}
for (NSString *airportList in objects) {
NSInteger sectionNumber = [self.collation sectionForObject:airportList collationStringSelector:#selector(city)];
[[newSectionArray objectAtIndex:sectionNumber] addObject:airportList];
}
for (index = 0; index < sectionTitleCount; index++) {
NSMutableArray *airportListArrayForSection = [newSectionArray objectAtIndex:index];
[newSectionArray replaceObjectAtIndex:index withObject:[self.collation sortedArrayFromArray:airportListArrayForSection collationStringSelector:#selector(city)]];
}
self.sectionArray = newSectionArray;
[self.table reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[[self.collation sectionTitles] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSMutableArray *airportListsInSection = (self.sectionArray)[section];
return [airportListsInSection count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[self.collation sectionTitles] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [[self.collation sectionIndexTitles] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [self.collation sectionForSectionIndexTitleAtIndex:index];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
....
Aiports *airportLists = (self.sectionArray)[indexPath.section][indexPath.row];
cell.textLabel.text = airportLists.city;
}

Zombie section headers in indexed list

I made indexed list according to this apple tutorial, but I have problem with deleting items. When I delete last item in section at the bottom, the section header remain there. This happens only with last section.
Here is my code for deleting item:
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[[self.littleWords objectAtIndex:indexPath.section]removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
littleWords is array of sections same as states in apple tutorial.
code for making cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"MyBasicCell"];
Word * myWord = [[self.littleWords objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.textLabel.text = myWord.name;
cell.detailTextLabel.text = myWord.translation;
return cell;
}
rest of tableView functions:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.littleWords count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.littleWords objectAtIndex:section] count];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [[UILocalizedIndexedCollation currentCollation] sectionIndexTitles];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if ([[self.littleWords objectAtIndex:section] count] > 0) {
NSString *str = [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:section];
NSLog(#"returning section header: %#", str);
return str;
}
return nil;
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return [[UILocalizedIndexedCollation currentCollation] sectionForSectionIndexTitleAtIndex:index];
}
The problem is in the method numberOfSectionsInTableView:. The number should change when you delete all of the items in a given section. Here is an example of what you can do:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger sections = 0;
for (NSArray *sectionArray in littleWords) {
if (sectionArray.count > 0) {
sections++;
}
}
return sections;
}
Edit: After deleting the row, you may need to call [tableView reloadData] or a similar methid to update the sections.

Resources