尝试从节和更新表中删除行(单元格)时索引超出界限(Xcode,Objective-c)

时间:2014-02-19 11:11:44

标签: ios objective-c uitableview cell sections

我有一个按部分分组的tableview,按日期排序,每个部分基本上是一天,每一行都是当天的约会/事件。我从一个nsmutablearray获取我的事件,并且它们有一个“startDate”属性,我通过该属性对表进行排序。我在尝试从部分删除行时遇到了麻烦。

- 如果我有1行5行,那么我可以单独删除它们,最后一行也会删除该部分。

- 如果我有超过1个部分,当我尝试删除部分中的最后一行时,它会崩溃。

这是我的代码:

 @interface AgendaViewController ()
@property (nonatomic,strong) NSString *path;
@property (strong, nonatomic) NSMutableDictionary *sections;
@property (strong, nonatomic) NSMutableArray *sortedDays;
@property (strong, nonatomic) NSDateFormatter *sectionDateFormatter;
@property (strong, nonatomic) NSDateFormatter *cellDateFormatter;
@end

@implementation AgendaViewController
@synthesize events = _events;
-(IBAction)menuButtonTapped:(id)sender{
    [self.slidingViewController anchorTopViewToRightAnimated:YES];

}
-(IBAction)unwindToAgenda:(UIStoryboardSegue *)segue{
    AddAgendaEntryViewController *source = [segue sourceViewController];
    AgendaEntry *event = source.agendaEntry;
    if (event){
        [self.events addObject:event];
        [self saveList];
        [self createSections];
        [self.tableView reloadData];
    }

}

- (void)saveList
{
    [NSKeyedArchiver archiveRootObject:self.events toFile:self.path];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    self.path = [self.path stringByAppendingPathComponent:@"TodoList.txt"];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:self.path]) {
        self.events = [[NSMutableArray alloc] init];
    } else {
        self.events = [[NSKeyedUnarchiver unarchiveObjectWithFile:self.path] mutableCopy];
    }

    [self setMenuGesture];
    [self fetchEvents];


    [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];
    self.tableView.separatorColor = [UIColor colorWithRed:224.0/255.0 green:224.0/255.0 blue:224.0/255.0 alpha:1.0f];

    [self createSections];
        //date formatteri

        self.sectionDateFormatter = [[NSDateFormatter alloc] init];
        [self.sectionDateFormatter setDateStyle:NSDateFormatterLongStyle];
        [self.sectionDateFormatter setTimeStyle:NSDateFormatterNoStyle];

        self.cellDateFormatter = [[NSDateFormatter alloc] init];
        [self.cellDateFormatter setDateStyle:NSDateFormatterNoStyle];
        [self.cellDateFormatter setTimeStyle:NSDateFormatterShortStyle];

    }


-(void)createSections{
    self.sections = nil;
    self.sections = [[NSMutableDictionary alloc]init];
    for (AgendaEntry *entry in self.events){
        NSDate *dateRepresentingThisDay = [self dateAtBeginningOfDayForDate:entry.startDate];
        NSMutableArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
        if(eventsOnThisDay == nil){
            eventsOnThisDay = [NSMutableArray array];
            [self.sections setObject:eventsOnThisDay forKey:dateRepresentingThisDay];

        }
        [eventsOnThisDay addObject:entry ];

        NSArray *unsortedDays =  [self.sections allKeys];

        self.sortedDays = [[unsortedDays sortedArrayUsingSelector:@selector(compare:)] mutableCopy];}

        NSLog(@"NUMBER OF SECTIONS IN TABLEVIEW: %lu",(unsigned long)[self.sections count]);
   // [self.tableView reloadData];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [self.sections count];
}







- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

}


-(void)fetchEvents{
    //Apel catre webserver pentru eventuri.
}

-(void)setEvents:(NSMutableArray *)events{
    _events = events;
    [self.tableView reloadData];
}

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

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:section];
    NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
    return [eventsOnThisDay count];
}

/*- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:section];
    NSString *title = [self.sectionDateFormatter stringFromDate:dateRepresentingThisDay];
    return title;
}*/
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) section{

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 15)];
    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, self.view.frame.size.width, 15)];
    lbl.backgroundColor = [UIColor clearColor];
    lbl.textAlignment = NSTextAlignmentCenter;
    lbl.font = [UIFont systemFontOfSize:12];

    NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:section];
    NSString *title = [self.sectionDateFormatter stringFromDate:dateRepresentingThisDay];
    lbl.text = title;

    [view addSubview:lbl];
    [view setBackgroundColor:[UIColor colorWithRed:166/255.0 green:177/255.0 blue:186/255.0 alpha:0.3]]; //your background color...
    return view;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Event Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    // Configure the cell..
    //AgendaEntry *event = [self.events objectAtIndex:indexPath.row];

    NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:indexPath.section];
    NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
    AgendaEntry *event = [eventsOnThisDay objectAtIndex:indexPath.row];

  UIImageView *mappin = (UIImageView *)[cell viewWithTag:4] ;
    mappin.image  = [UIImage imageNamed:@"map_pin"];

    UILabel *companyName = (UILabel *)[cell viewWithTag:1];
    companyName.text = event.companyName;

    UILabel *eventType = (UILabel *) [cell viewWithTag:3];
    eventType.text = event.eventType;

    UILabel *dateOfEvent = (UILabel *) [cell viewWithTag:2];

    dateOfEvent.text = [self.cellDateFormatter stringFromDate:event.startDate];
    return cell;
}


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source

        [self.events removeObjectAtIndex:indexPath.row];
        [self createSections];

        [self saveList];

        [tableView beginUpdates];
        NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:indexPath.section];
        NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
        if ([eventsOnThisDay count] > 0){

        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        }else{
        [tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
                 withRowAnimation:UITableViewRowAnimationFade];


}
        [tableView endUpdates];
    }
    [self.tableView reloadData];
}

-(NSMutableArray *)sortedDays{
    if (!_sortedDays) _sortedDays = [[NSMutableArray alloc]init];
    return _sortedDays;
}


-(void)setMenuGesture{
    id<ECSlidingViewControllerDelegate> transition = self.zoomAnimationController ;
    self.slidingViewController.delegate = transition;
    self.slidingViewController.topViewAnchoredGesture = ECSlidingViewControllerAnchoredGestureTapping | ECSlidingViewControllerAnchoredGesturePanning;
    self.slidingViewController.customAnchoredGestures = @[];

  //  [self.navigationController.view addGestureRecognizer:self.slidingViewController.panGesture];
}

- (ZoomAnimationController *)zoomAnimationController {
    if (_zoomAnimationController) return _zoomAnimationController;

    _zoomAnimationController = [[ZoomAnimationController alloc] init];

    return _zoomAnimationController;
}

-(NSMutableArray *)events{
    [self sortEvents];
    return _events;
}
/*- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 30;
}*/

- (NSDate *)dateAtBeginningOfDayForDate:(NSDate *)inputDate
{
    // Use the user's current calendar and time zone
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
    [calendar setTimeZone:timeZone];

    // Selectively convert the date components (year, month, day) of the input date
    NSDateComponents *dateComps = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:inputDate];

    // Set the time components manually
    [dateComps setHour:0];
    [dateComps setMinute:0];
    [dateComps setSecond:0];

    // Convert back
    NSDate *beginningOfDay = [calendar dateFromComponents:dateComps];
    return beginningOfDay;
}


-(void)sortEvents{
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"startDate" ascending:TRUE];
    [_events sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

}
@end

我得到的错误:

  

由于未捕获的异常'NSRangeException'而终止应用程序,原因:'*** - [__ NSArrayM objectAtIndex:]:索引1超出边界[0 .. 0]'`

3 个答案:

答案 0 :(得分:0)

使用yourArray [removeObjectAtIndex:indexpath];它会更新你的数组。

答案 1 :(得分:0)

commitEditingStyle功能中,您首先删除该部分(我假设在这种情况下为第1部分......),然后在[tableView beginUpdates];[tableView endUpdates];行之间更新您的表格。您遇到的问题是您使用原始部分索引(1)访问您的sortedDays数组,该索引不再存在 - 您刚删除它; - ):

  

NSDate * dateRepresentingThisDay = [self.sortedDays   objectAtIndex:indexPath.section];

答案 2 :(得分:0)

deleteForRowAtIndexPath中的逻辑似乎导致了这个问题。 您正在做的只是根据self.eventsindexPath.row删除。但是当您有超过1个部分时,您的self.eventseventsOnThisDay数组可能不会保持相同的索引。

我建议您以与将其加载到tableView相同的方式删除该项目。例如,在deleteRowAtIndexPath

NSDate *dateRepresentingThisDay = [self.sortedDays objectAtIndex:indexPath.section];
NSArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
[eventsOnThisDay removeObjectAtIndex:indexPath.row];
//If there are no more events on this day, then just delete the section also.
if([eventsOnThisDay count] == 0){
   [self.sections removeObjectForKey:dateRepresentingThisDay];
   [self.sortedDays removeObjectAtIndex:indexPath.section];
}
[self.tableView reloadData];
//You should also update your self.events list also accordingly.

希望这有帮助。