I am trying to add a new row to my custom cell with an NSMutablearray from another viewcontroller but I am getting an error when a new row is added. itemsTableView is visible in photoCaptureView which is the view for photoCaptureViewController. So when ScannerModalViewController (which is being called also in photoCaptureViewController) is called and capture the item/data and once it is dismissed scannedBarcode is called to add a new row to my custom cell and populate it I'm getting this error.
I am getting a warning and an error. The warning is
Warning once only: UITableView was told to layout its visible cells and other contents without
being in the view hierarchy (the table view or one of its superviews has not been added to a
window). This may cause bugs by forcing views inside the table view to load and perform layout
without accurate information (e.g. table view bounds, trait collection, layout margins, safe
area insets, etc), and will also cause unnecessary performance overhead due to extra layout
passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch
this in the debugger and see what caused this to occur, so you can avoid this action altogether
if possible, or defer it until the table view has been added to a window. Table view:
<UITableView: 0x1038a9c00; frame = (10 70; 398 794); clipsToBounds = YES; gestureRecognizers =
<NSArray: 0x28165f0c0>; layer = <CALayer: 0x2818ebb20>; contentOffset: {0, 0}; contentSize:
{398, 60}; adjustedContentInset: {0, 0, 0, 0}; dataSource: <PhotoCaptureViewController: 0x10364a880>>
error is
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing
section after the update (3) must be equal to the number of rows contained in that section
before the update (1), plus or minus the number of rows inserted or deleted from that section
(1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section
(0 moved in, 0 moved out).
My code is photoCaptureViewController.h
#interface PhotoCaptureViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, ScannerModalViewControllerDelegate> {
PhotoCaptureView* photoCaptureView;
NSMutableArray* barcodeItems;
ScannerModalViewController* scannerModalViewController;
}
-(void) scanBarcode;
-(void) scannedBarcode:(NSString *) barcode;
#end
photoCaptureViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[photoCaptureView.itemsTableView registerNib:[UINib nibWithNibName:#"BarcodeItemsTableViewCell" bundle:nil] forCellReuseIdentifier:#"BarcodeItemsCell"];
photoCaptureView.itemsTableView.rowHeight = 60;
photoCaptureView.itemsTableView.dataSource = self;
photoCaptureView.itemsTableView.delegate = self;
[photoCaptureView.itemsTableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
}
#pragma mark scannerModalViewController Methods
-(void) scanBarcode {
NSLog(#"[%#] Scan Barcode Requested", self.class);
scannerModalViewController = [[ScannerModalViewController alloc] init];
scannerModalViewController.delegate = self;
scannerModalViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:scannerModalViewController animated:YES completion:nil];
}
-(void) scannedBarcode:(NSMutableArray *) barcodes {
barcodeItems = [[NSMutableArray alloc] init];
[barcodeItems addObjectsFromArray:barcodes];
[barcodeItems addObject:#"test"];
[barcodeItems addObject:#"test1"];
NSLog(#"%#", barcodes);
NSLog(#"%#", barcodeItems);
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:barcodeItems.count-1 inSection:0];
[photoCaptureView.itemsTableView beginUpdates];
[photoCaptureView.itemsTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[photoCaptureView.itemsTableView endUpdates];
}
#pragma mark UITableViewDataSource methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return barcodeItems.count + 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Cell Initialized");
static NSString *cellIdentifier = #"BarcodeItemsCell";
BarcodeItemsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (cell == nil) {
cell = [[BarcodeItemsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell...
cell.barcodeLabel.text = [barcodeItems objectAtIndex:indexPath.row];
UIImage *btnImage = [UIImage imageNamed:#"barcodeIcon"];
[cell.leftButton setImage:btnImage forState:UIControlStateNormal];
NSLog(#"Cell Populated");
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return true;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[barcodeItems removeObjectAtIndex:indexPath.row];
[photoCaptureView.itemsTableView beginUpdates];
[photoCaptureView.itemsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[photoCaptureView.itemsTableView endUpdates];
}
}
#end
If you insert the items with insertRowsAtIndexPaths you have to specify all paths.
And beginUpdates /endUpdates` has no effect for a single insert/delete/move operation.
-(void) scannedBarcode:(NSMutableArray *) barcodes {
barcodeItems = [[NSMutableArray alloc] init];
[barcodeItems addObjectsFromArray:barcodes];
[barcodeItems addObject:#"test"];
[barcodeItems addObject:#"test1"];
NSLog(#"%#", barcodes);
NSLog(#"%#", barcodeItems);
NSMutableArray<NSIndexPath *>* indexPaths = [[NSMutableArray alloc] init];
for (i = 0; i < barcodeItems.count; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[photoCaptureView.itemsTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
And numberOfRowsInSection must return
return barcodeItems.count;
Related
How top expand collapse custom cell tableview and expanding the cell must be dynamic height in iOS objective c?
viewcontroller having custom tableview cells when click on the cell,cell must be expand/collapse having one view and display data in that view and height must be dynamic
You'll have to maintain a state (expanded/not expanded) for the custom table view cell. Every time it's tapped you make the necessary changes in the UI and toggle the state. You can then call
reloadData()
or
-(void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths
withRowAnimation:(UITableViewRowAnimation)animation;
You can also calculate and set the new height of the cell and the reload function will take care of the animation.
You used tableview then easy manage expand and collapse custom cell tableview and expanding with animation.
Follow code for expand and collapse.
.h File
BOOL currentlyExpanded;
NSMutableIndexSet *expandedSections;
.m File
- (void)viewDidLoad
{
if (!expandedSections)
{
expandedSections = [[NSMutableIndexSet alloc] init];
}
}
Use Tableview Delegate and Datasource method..
#pragma mark - Tableview Delegate -
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section
{
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
return 6; //return your array count..
else
return 1;
}
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier]
;
}
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
//Display your dynamic cell contain..
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self tableView:tableView canCollapseSection:indexPath.section])
{
NSInteger section = indexPath.section;
currentlyExpanded = [expandedSections containsIndex:section];
NSInteger rows;
if (currentlyExpanded)
{
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
}
else
{
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
}
// Animation when cell expand and collapse
if(currentlyExpanded)
{
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
CGFloat startRadians, endRadians;
startRadians = M_PI/2;
endRadians = 0.0f;
btnArrow.layer.affineTransform = CGAffineTransformMakeRotation(startRadians);
[UIView animateWithDuration:0.3f animations:^{
btnArrow.layer.affineTransform = CGAffineTransformMakeRotation(endRadians);
}completion:^(BOOL finished){
}];
}
else
{
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationTop];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[btnArrow setTransform:CGAffineTransformRotate(btnArrow.transform, M_PI/2 )];
}completion:^(BOOL finished){
}];
}
}
}
So i have been trying for a little while now to create a table view with expandable sections and one non expandable section. One of the expandable sections should have 3 text fields inside them in which you can edit the test inside the text field. I was able to get that working bt the moment you collapse the section and expand it again the textfield suddenly duplicates itself above and sometimes swaps itself out with the above cell. Ihavent been able to figure out why or how to make it not do that.
The idea is when the user enters text in the field and selects enter the text is stored into an array.
the code:
- (void)viewDidLoad{
[super viewDidLoad];
if (!expandedSections){
expandedSections = [[NSMutableIndexSet alloc] init];
}
manualSensorName = [[NSMutableArray alloc]initWithObjects: #"Sensor",#"",#"2",#"T", nil];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Expanding
- (BOOL)tableView:(UITableView *)tableView canCollapseSection:(NSInteger)section{
if (section>0) return YES;
return NO;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if ([self tableView:tableView canCollapseSection:section])
{
if ([expandedSections containsIndex:section])
{
return 5; // return rows when expanded
}
return 1; // only top row showing
}
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
if ([self tableView:tableView canCollapseSection:indexPath.section]){
if (!indexPath.row){
// first row
cell.textLabel.text = #"Expandable"; // only top row showing
if ([expandedSections containsIndex:indexPath.section])
{
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowUP.png"]];
cell.accessoryView = arrow;
}
else
{
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowDOWN.png"]];
cell.accessoryView = arrow;
}
}
else {
if (indexPath.row == 1){
NSString *flightNumText = [manualSensorName objectAtIndex:indexPath.row];
cell.textLabel.text = flightNumText;
}
else if (indexPath.row == 2){
txtManualSensor = [[UITextField alloc] initWithFrame:CGRectMake(180, 5, 120, 30)];
txtManualSensor.placeholder = #"Select";
txtManualSensor.delegate = self;
txtManualSensor.autocorrectionType = UITextAutocorrectionTypeNo;
txtManualSensor.backgroundColor = [UIColor whiteColor];
[txtManualSensor setBorderStyle:UITextBorderStyleBezel];
[txtManualSensor setTextAlignment:NSTextAlignmentCenter];
[txtManualSensor setReturnKeyType:UIReturnKeyDone];
// UITextField *playerTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 5, 120, 30)];
// playerTextField.adjustsFontSizeToFitWidth = YES;
// playerTextField.textColor = [UIColor blackColor];
// playerTextField.placeholder = #"SAMPLE";
// playerTextField.tag = 200;
// playerTextField.delegate = self;
// [cell.contentView addSubview:playerTextField];
cell.textLabel.text = #"Sensor Name";
[cell addSubview:txtManualSensor];
}
else if (indexPath.row == 3){
cell.textLabel.text = #"Some Detail";
cell.accessoryView = nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
}
else {
cell.accessoryView = nil;
cell.textLabel.text = #"Normal Cell";
}
return cell;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[manualSensorName replaceObjectAtIndex:2 withObject:textField.text];
return YES;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([self tableView:tableView canCollapseSection:indexPath.section]){
if (!indexPath.row){
[tableView beginUpdates];
// only first row toggles exapand/collapse
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger section = indexPath.section;
BOOL currentlyExpanded = [expandedSections containsIndex:section];
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
if (currentlyExpanded) {
rows = [self tableView:tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
}
else {
[expandedSections addIndex:section];
rows = [self tableView:tableView numberOfRowsInSection:section];
}
for (int i=1; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (currentlyExpanded) {
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowDOWN.png"]];
[tableView deleteRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationFade];
cell.accessoryView = arrow;
}
else {
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"arrowUP.png"]];
[tableView insertRowsAtIndexPaths:tmpArray
withRowAnimation:UITableViewRowAnimationFade];
cell.accessoryView = arrow;
}
NSLog(#"tableview row is %ld in section %ld",(long)indexPath.row,(long)indexPath.section);
[tableView endUpdates];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"selected row is %ld in section %ld",(long)indexPath.row,(long)indexPath.section);
if (indexPath.row == 1) {
// update text fields in cell table view
}
}
}
It may be as simple as replacing UITableViewRowAnimationTop by UITableViewRowAnimationFade:
When changing indexes in didSelectRowAtIndexPath, UITableViewCells change physical location (remember that the UITableView is a UIScrollView), and the scroller can't keep track of what your intent is.
UITableViewRowAnimationTop attempts to adjust the scrolling location, but fails.
Other design considerations:
Do not mix the model (the array of data to be displayed) with your view model (the UI displaying the model). In didSelectRowAtIndexPath, you should first re-order your model, then apply it to the cells
Consider not changing indexes on the fly: you may prefer a model that actually reflects the view structure, i.e. a tree.
Have you noticed you are not respecting - (void)tableView:(UITableView *)tableView and sometimes using self tableView:tableView or self.customTableView in the same method? You should use the tableView passed to you.
I have a thread problem SIGABRT when i try to add one more cell in my app; That is the exception which Xcode gave me:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
That is the code where i consider is the problem
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PlayerCell *cell = (PlayerCell *)[tableView
dequeueReusableCellWithIdentifier:#"PlayerCell"];
Player *player = [self.players objectAtIndex:indexPath.row];
cell.nameLabel.text = player.name;
cell.gameLabel.text = player.game;
cell.ratingImageView.image = [self
imageForRating:player.rating];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.players removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade]; }
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.players count];
}
UPD.
I have an array in AppDelegate to preconfig several cells (to show user, how it looks like) and full it with follow code:
_players = [NSMutableArray arrayWithCapacity:20]; // make an array in appdelegate
Player *player = [[Player alloc] init]; //
player.name = #"Bill Evans"; //
player.game = #"Tic-Tac-Toe"; //Make new player
player.rating = 4; //
[_players addObject:player]; //Add in array in AppDelegate
PlayersViewController *playersViewController = [PlayersViewController new]; //Make instance for main array
playersViewController.players = _players; //add new item from appDelegate array to main
Another piece of code where the mistake may be (it loads when user taps on save button to add new cell)
- (void)playerDetailsViewController:
(PlayerDetailsViewController *)controller
didAddPlayer:(Player *)player
{
[self.players addObject:player];
NSIndexPath *indexPath =
[NSIndexPath indexPathForRow:[self.players count] - 1 inSection:0];
[self.tableView insertRowsAtIndexPaths:
[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self dismissViewControllerAnimated:YES completion:nil];
}
So can anyone tell me, where is my mistake? If needed, i can send further code.
Thanks.
I try to do so as in the picture shown in red square.
I need by clicking a user opens a plate and DatePicker. For this I use Expandable UITableView (http://www.wannabegeek.com/?p=338). But I can not understand how to do so in the section could is one element (eg DatePicker) and by clicking on the section shows exactly DatePicker. Now, if at least two elements, then the string is not displayed as a section, but as just a string containing no more elements. And as if I did not change the size of the prototype cell size does not change and I can not see completely DatePicker. Now my DatePicker is behind the text of the cell (which is logical)
Two main questions: how to change the size of the cell, that is normal to see DatePicker and how to make that you can have only one item in the list
In StoryBoard I see:
In simulator:
May have the decision easier?
I use the code:
// Exampl2eController.m
#import "Example2Controller.h"
#implementation Example2Controller
#synthesize dataModel = _dataModel;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_dataModel = [NSMutableArray arrayWithObjects:
[NSMutableArray arrayWithObjects:#"Row 1a", #"Row 2a", #"Row 3a", nil],
[NSMutableArray arrayWithObjects:#"Row 1b", #"Row 2b", nil],
[NSMutableArray arrayWithObjects:#"Row 1c", #"Row 2c", #"Row 3c", #"Row 4c", nil],
[NSMutableArray arrayWithObjects:#"Row 1d", nil],
nil];
}
- (NSInteger)numberOfSectionsInTableView:(ExpandableTableView *)tableView
{
// Return the number of sections.
return [_dataModel count];
}
- (NSInteger)tableView:(ExpandableTableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([_dataModel count] == 0) {
return 0;
}
// Return the number of rows in the section.
return [[_dataModel objectAtIndex:section] count];
}
- (UITableViewCell *)tableView:(ExpandableTableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"RowCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [[_dataModel objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
// just change the cells background color to indicate group separation
cell.backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
cell.backgroundView.backgroundColor = [UIColor colorWithRed:232.0/255.0 green:243.0/255.0 blue:1.0 alpha:1.0];
return cell;
}
- (UITableViewCell *)tableView:(ExpandableTableView *)tableView cellForGroupInSection:(NSUInteger)section
{
static NSString *CellIdentifier = #"GroupCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [NSString stringWithFormat: #"Group %d (%d)", section, [self tableView:tableView numberOfRowsInSection:section]];
// We add a custom accessory view to indicate expanded and colapsed sections
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"ExpandableAccessoryView"] highlightedImage:[UIImage imageNamed:#"ExpandableAccessoryView"]];
UIView *accessoryView = cell.accessoryView;
if ([[tableView indexesForExpandedSections] containsIndex:section]) {
accessoryView.transform = CGAffineTransformMakeRotation(M_PI);
} else {
accessoryView.transform = CGAffineTransformMakeRotation(0);
}
return cell;
}
// The next two methods are used to rotate the accessory view indicating whjether the
// group is expanded or now
- (void)tableView:(ExpandableTableView *)tableView willExpandSection:(NSUInteger)section {
UITableViewCell *headerCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
[UIView animateWithDuration:0.3f animations:^{
headerCell.accessoryView.transform = CGAffineTransformMakeRotation(M_PI - 0.00001); // we need this little hack to subtract a small amount to make sure we rotate in the correct direction
}];
}
- (void)tableView:(ExpandableTableView *)tableView willContractSection:(NSUInteger)section {
UITableViewCell *headerCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
[UIView animateWithDuration:0.3f animations:^{
headerCell.accessoryView.transform = CGAffineTransformMakeRotation(0);
}];
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(ExpandableTableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (BOOL)tableView:(ExpandableTableView *)tableView canEditSection:(NSInteger)section {
return YES;
}
// Override to support editing the table view.
- (void)tableView:(ExpandableTableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[[_dataModel objectAtIndex:indexPath.section] removeObjectAtIndex:indexPath.row];
// cellVisibleForIndexPath: isn't strictly required sicne the table view will determine if the
// the row at that indexPath is actually visible, and do the appropriate manipulation
if ([(ExpandableTableView *)tableView cellVisibleForIndexPath:indexPath]) {
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
if ([[_dataModel objectAtIndex:indexPath.section] count] == 0) {
[_dataModel removeObjectAtIndex:indexPath.section];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
} else {
[tableView reloadSectionCellsAtIndexes:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
[tableView endUpdates];
}
// Override to support rearranging the table view.
- (void)tableView:(ExpandableTableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(ExpandableTableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
- (BOOL)tableView:(ExpandableTableView *)tableView canRemoveSection:(NSUInteger)section {
return YES;
}
#end
There is an ivar called: _ungroupSingleElement set it to false and then you disable this feature
I am parsing XML that gets the first 25 items in my MySQL database using PHP - LIMIT and GET. When I click on the "Load More" cell that I append to the bottom of my tableview, it successfully gets the next 25 items, but only loads the first 40 and leaves off the last 10. Each time I click on the "Load more" cell it add 25 to my range (ie 0-25,25-50), but it seems that my range caps at 65 and the display caps at 40.
Here is my load more function thats not working:
-(void) getNewRange{
int currentRange = [allItems count];
int newRange = currentRange + 25;
if(newRange > [xmlParser total]){
NSLog(#"evaluating as greater than the total, which is 837");
newRange = [xmlParser total];
}
NSString *range = [[NSString alloc] initWithFormat:#"?range=%d&range2=%d",currentRange,newRange];
NSString *newUrl =[[NSString alloc] initWithFormat:#"http://localhost/fetchAllTitles.php%#",range];
XMLParser *tempParser = [[XMLParser alloc] loadXMLByURL:newUrl];
[allItems addObjectsFromArray:[tempParser people]];
NSMutableArray *newCells = [[NSMutableArray alloc] initWithCapacity:25];
for(int i=currentRange;i<newRange;i++){
NSLog(#"%d",i);
NSIndexPath *indexpath=[NSIndexPath indexPathForRow:i inSection:0];
[newCells addObject:indexpath];
}
NSLog(#"%#",newUrl);
[self.tableView insertRowsAtIndexPaths:newCells withRowAnimation:UITableViewRowAnimationAutomatic];
}
I'm getting closer, but I get this new error:
*** Assertion failure in -[_UITableViewUpdateSupport _computeRowUpdates], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableViewSupport.m:386
Read up on how you can Reuse your table view's cells.
Your data does not need to be 'owned' by the cell.
UITableView isn't a class to contain your data, and you shouldn't try to directly micromanage what cells it displays. As another poster stated, read up on how to use it. What you should do is:
-(void)loadNewData
{
NSIndexPath *index;
XMLParser *tempParser = [[XMLParser alloc] loadXMLByURL:newUrl];
NSArray *people=[tempParser people];
for(id *person in people)
{
[self.dataArray addObject:person];
indexPath=[NSIndexPath indexPathForRow:[self.dataArray indexForObject:person] inSection:0];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [AnArray count];//use whatever array stores your data
}
//If you've subclassed the cell, adjust appropriately.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
//Customize the cell
return cell;
}
The table view will take care of all the logic involved in displaying the cells, if you let it. This way, you only have a limited number of cells taking up memory at any given time, and you don't have to handle that -- the table view automagically handles reusing the cells, and knowing how many are needed as a buffer before / after.
you should not set numberOfRowsInSection inside your method. The number of rows should get returned from the tableView's datasource method - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section. Just return [allItems count] there.