“Attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update” Error

拈花ヽ惹草 提交于 2019-12-10 01:45:55

问题


I have an app that is selecting a person from their contacts list and takes their First name, last name and email. It then saves the first name to a nsmutablearray and puts it into a uitableview cell. My problem occurs once the contact is selected in the simulator.

Code:

.h:

#import <UIKit/UIKit.h>
#import <AddressBookUI/AddressBookUI.h>

@interface FirstViewController : UIViewController <    ABPeoplePickerNavigationControllerDelegate, UITableViewDelegate, UITableViewDataSource>

- (IBAction)showPicker:(id)sender;

@property (weak, nonatomic) IBOutlet NSString *firstName;

@property (weak, nonatomic) IBOutlet NSString *email;

@property (weak, nonatomic) IBOutlet NSString *lastName;


@property (weak, nonatomic) IBOutlet UITableView *myTableView;

@property (strong, nonatomic) NSMutableArray *contacts;

@end

.m:

#import "FirstViewController.h"

@interface FirstViewController ()

@end

@implementation FirstViewController

@synthesize firstName;

@synthesize email;

@synthesize lastName;

@synthesize contacts;

@synthesize myTableView;


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    contacts = [[NSMutableArray alloc]initWithObjects:nil];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - UITableView Datasource

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
} 

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return contacts.count;
}

-(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];

    }

    cell.textLabel.text = [contacts objectAtIndex:indexPath.row];

    return cell;
}

- (IBAction)showPicker:(id)sender {

    ABPeoplePickerNavigationController *picker =
    [[ABPeoplePickerNavigationController alloc] init];
    picker.peoplePickerDelegate = self;

    [self presentModalViewController:picker animated:YES];
}

- (void)peoplePickerNavigationControllerDidCancel:
(ABPeoplePickerNavigationController *)peoplePicker
{
    [self dismissModalViewControllerAnimated:YES];
}


- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person {

    [self displayPerson:person];
    [self dismissModalViewControllerAnimated:YES];

    return NO;
}

- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier
{





    return NO;

}


- (void)displayPerson:(ABRecordRef)person
{
    NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person,
                                                                    kABPersonFirstNameProperty);
    self.firstName = name;

    NSString* last = (__bridge_transfer NSString*)ABRecordCopyValue(person,
                                                                    kABPersonLastNameProperty);
    self.lastName = last;


    ABMultiValueRef  emails = ABRecordCopyValue(person, kABPersonEmailProperty);
    NSString *emailId = (__bridge NSString *)ABMultiValueCopyValueAtIndex(emails, 0);//0     for "Home Email" and 1 for "Work Email".

    self.email = emailId;

    if (!(contacts))
    {

        contacts = [[NSMutableArray alloc]init];

    }

    [contacts insertObject:firstName atIndex:0];

    NSIndexPath * indexPath = [NSIndexPath indexPathForRow:0 inSection:0];

    [self.myTableView insertRowsAtIndexPaths:@[indexPath]  withRowAnimation:UITableViewRowAnimationAutomatic];
}




@end

回答1:


UITableView must be kept in sync with the data source at all times. Special care must be taken if the data source can change in a background thread.

When something is added to the data source, call beginUpdate/insert/endUpdate as soon as possible. You don't have to worry about caching these, the UITableView will cache changes to be executed when it determines there is enough cpu time and resources.

The moment endUpdates is called, the UITable will ask the dataSource for the number of sections and rows again. If your number of sections and row feeds directly from the dataSource, then number sections and rows, plus insertions, minus deletions must equal the numbers returned by the end calls for numberOfSections and numberOfRowsInSection.

One last tip: avoid mixing calls to 'reloadData' and beginUpdate/endUpdate pairs. Use one or the other, not both.




回答2:


I have encountered same problem as this. All you have to do is change

[self.myTableView insertRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationAutomatic];`

to

 [self.myTableView beginUpdates];

 [self.myTableView insertRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationAutomatic];

 [self.myTableView endUpdates];

From UITableView Documentation

beginUpdates

Begin a series of method calls that insert, delete, or select rows and sections of the receiver.

when you use beginUpdates, you must call endUpdates and not reloadData.

You can check https://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html for more UITableView information.

Hope this helps!




回答3:


The comments above about implementing -tableView:numberOfRowsInSection: are correct. The assertion is checking the returned value expecting it will increase.

However since you didn't set your dataSource on the UITableView its calling (or not calling) a method that doesn't exist and getting 0.

You need to set the myTableView.dataSource and (since you also implement the delegate protocol) myTableView.delegate to self.

You're also likely to need something like

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.myTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
    ...
}

Unless you're registering that somewhere else or your storyboard has a "Prototype Cell" with the identifier "Cell" which your code asks for.




回答4:


I find this problem commonly occurs when I am placing a table view inside of a View Controller. If you're using a UITableViewController jump to 3.

These steps may help:

1: In your View Controller .h file make sure you add the following:

@interface YourViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>

2: Next create an IBOutlet for your table view by ctrl + drag to your .h class. It should look like:

@property (weak, nonatomic) IBOutlet UITableView *tableView;

3: Next step is to ctrl + drag to your View Controllers icon (see image)

You need to do this twice selecting:

- delegate
- datasource

Finally, in your .m file, you should have the following method:

- (void) viewWillAppear:(BOOL)animated{
    //[self.tableView beginUpdates];
    //[self.tableView endUpdates];

    [self.tableView reloadData];
}

You can use either beginUpDates/endUpdates or reloadData, however Apple docs recommend reloadData.

Once done your table should work fine.




回答5:


You need to maintain count for contacts array and increment accordingly.
and while creating indexPath you need to set appropriate indexPathForRow: and section count(if required).

- (void)displayPerson:(ABRecordRef)person
{

  ..........

[contacts insertObject:firstName atIndex:0];

NSIndexPath * indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; // you cant do this increment appropriately

 .........
}



回答6:


Please check your tableview datasource and delegate methods. You may be passing empty array to datasource methods. And don't forget to reload tableview after getting data.




回答7:


I know it's stupid - I got the same error because I forgot to set the delegate and dataSource.

So after inserting rows and doing tableView.endUpdates() the tableView thought it must have some rows - but due to the unlinked dataSource, it has not.



来源:https://stackoverflow.com/questions/17005635/attempt-to-insert-row-0-into-section-0-but-there-are-only-0-rows-in-section-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!