2013-11-07 2 views
2

Я просто застрял здесь, я не могу понять, что я делаю неправильно здесь. Я довольно новичок в объективе c. В моей заявке я использую UITableView и NSMutableArray для анализа данных из RSS-канала. Я хочу обновить всю таблицу новыми данными, когда пользователь нажимает на элемент управления сегмента в представлении таблицы. Я добавил элемент управления сегментами в заголовок таблицы, и он отлично работает с изменением значения при изменении индекса сегмента.NSMutableArray в UITableView

Проблема теперь, когда я нажимаю на элемент управления сегмента, он добавляет новые строки в tableview вместо обновления всей таблицы. Вот код:

- (void)addEarthquakesToList:(NSArray *)earthquakes 
    { 
    //NSInteger startingRow = [self.earthquakeList count]; 
    NSInteger earthquakeCount = [earthquakes count]; 
    NSMutableArray *indexPaths = [[NSMutableArray alloc] initWithCapacity:earthquakeCount]; 
    NSLog(@"%d",earthquakeCount); 

    for (NSInteger row = 0; row < (earthquakeCount); row++) 
    { 
     NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0]; 
     [indexPaths addObject:indexPath]; 
    } 

    [self.earthquakeList addObjectsFromArray:earthquakes]; 
    [self.tableView insertRowsAtIndexPaths:indexPaths 
          withRowAnimation:UITableViewRowAnimationAutomatic]; 
} 

Я пробовал много других вещей, как [self.tableView reloadData];
Я также попытался следующие действия, чтобы удалить все объекты из массива и удалить строки из таблицы, но не отображается правильное количество строк:

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
      fromLocation:(CLLocation *)oldLocation 
{ 
    NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init]; 

    for(unsigned int i = 0; i < [self.earthquakeList count]; i++) 
    { 
     [indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:0]]; 
    } 

    //[self.tableView beginUpdates]; 
    [self.earthquakeList removeAllObjects]; 
    [self.tableView deleteRowsAtIndexPaths:indexPathsToDelete 
          withRowAnimation:UITableViewRowAnimationFade]; 
    //[self.tableView endUpdates]; 
    //[self.tableView reloadData]; 
} 

И это мои Tableview методы DataSource:

- (NSInteger)tableView:(UITableView *)tableView 
numberOfRowsInSection:(NSInteger)section 
{ 
    // The number of rows is equal to the number of earthquakes in the array. 
    return [self.earthquakeList count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView 
     cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *kEarthquakeCellID = @"EarthquakeCellID"; 
    citsTableViewCell *cell = (citsTableViewCell *)[tableView dequeueReusableCellWithIdentifier:kEarthquakeCellID]; 

    //Get the specific earthquake for this row. 
    citsFuelFinder *earthquake = (self.earthquakeList)[indexPath.row]; 
    [cell configureWithEarthquake:earthquake]; 
    return cell; 
} 

На самом деле при попытке включить следующие управления сегмента:

- (void)segmentedControlHasChangedValue 
{ 
    int product; 
    product = fuelType.selectedSegmentIndex; 

    switch (product) 
    { 
     case 0: 
      productName=1; 
      [locationManager startUpdatingLocation]; 
      break; 

     case 1: 
      productName=2; 
      //[self.earthquakeList removeLastObject]; 
      if (![self.earthquakeList count]) 
      { 
       [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:0] 
           withRowAnimation:UITableViewRowAnimationRight]; 
      } 
      else 
      { 
       NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init]; 
       for(unsigned int i = 0; i < [self.earthquakeList count]; i++) 
       { 
        [indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i 
                    inSection:0]]; 
       } 
       //[self.tableView beginUpdates]; 
       //[self.earthquakeList removeAllObjects]; 
       [self.tableView deleteRowsAtIndexPaths:indexPathsToDelete 
             withRowAnimation:UITableViewRowAnimationFade]; 
       //[self.tableView endUpdates]; 
       [self.tableView reloadData]; 
       //[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; 
      } 
      [locationManager startUpdatingLocation]; 
      break; 

     case 2: 
      productName=4; 
      [locationManager startUpdatingLocation]; 
      break; 

     case 3: 
      productName=5; 
      [locationManager startUpdatingLocation]; 
      break; 

     default: 
      break; 
    } 
} 

Я получаю эту ошибку:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (15) must be equal to the number of rows contained in that section before the update (15), plus or minus the number of rows inserted or deleted from that section (0 inserted, 15 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).' * First throw call stack: (0x2e332e83 0x3868f6c7 0x2e332d55 0x2ecdb0af 0x30c8a34d 0x30cb083f 0x6d2d9 0x30aebda3 0x30aebd3f 0x30aebd13 0x30ad7743 0x30bf7c59 0x30bf7a27 0x30cbca25 0x30aaf1a1 0x30ae69fd 0x30ae63ab 0x30abbd79 0x30aba569 0x2e2fdf1f 0x2e2fd3e7 0x2e2fbbd7 0x2e266471 0x2e266253 0x32fa02eb 0x30b1b845 0x6948d 0x38b88ab7)

Любая помощь очень ценится!

+0

Так что вы пытаетесь сделать, это всегда таблица отображения данных 'self.earthquakeList' и очищать указанные данные всякий раз, когда происходит обновление? Правильно ли я понимаю это? –

+0

да, тот точно правый. Спасибо Carl – Tajuddin

+3

нет необходимости вставлять новые строки. Вы можете изменить источник данных (earthquakeList) и перезагрузить tableview –

ответ

0

Обновить исходный массив таблицы, нет необходимости вставлять новые строки.

[self.earthquakeList addObjectsFromArray:earthquakes]; 
[self.tableView reloadData]; 
+0

Я пробовал это, но он не обновляет данные таблицы. – Tajuddin

0

Если вы добавляете элементы в массив источников данных, нет. строк в представлении таблицы будет обновляться автоматически. Вам не нужно вставлять строки. Просто вставьте элементы. Реализовать свой метод, как:

- (void)addEarthquakesToList:(NSArray *)earthquakes 
{ 
    [self.earthquakeList addObjectsFromArray:earthquakes]; 
    [self.tableview reloadData]; 
} 
0

ERM, вместо

[self.tableView insertRowsAtIndexPaths:indexPaths 
         withRowAnimation:UITableViewRowAnimationAutomatic]; 

попробовать

[self.tableView reloadRowsAtIndexPaths:indexPaths 
         withRowAnimation:UITableViewRowAnimationAutomatic]; 

в любом случае .... ваши фрагменты кода еще недостаточно, для меня по крайней мере, чтобы найти вашу проблему.

Но так как вы сказали:
I want to refresh the whole table with new data when user click on the segment control in the tableview.

Если я должен был сделать сегментированный Tableview с 4 сегментами, который отображает различные данные для разных сегментов, я бы это сделать:

Примечание: это базовый пример. он не соответствует вашему конкретному коду, но должен дать вам идею отказаться от логики игры с помощью indexPaths или того, что вручную добавляет/удаляет объекты из массива и вместо этого использует tableView reloadData.

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    //declare NSArray *arrFirst, *arrSecond, *arrThird, *arrFourth, *arrSelected 
    //in the .h file 

    arrFirst = [[NSArray alloc] initWithObjects:@"eins",@"zwei",@"drei",@"vier",@"fünf",@"sechs", nil]; 
    arrSecond = [[NSArray alloc] initWithObjects:@"one",@"two",@"three",@"four",@"five",@"six",@"seven",@"eigth",@"nine", nil]; 
    arrThird = [[NSArray alloc] initWithObjects:@"uno",@"dos",@"tres",@"cuatro",@"cinco", nil]; 
    arrFourth = [[NSArray alloc] initWithObjects:@"ek",@"do",@"teen",@"chaar",@"paach",@"che",@"saat", nil]; 

    arrSelected = arrFirst; 
} 

- (IBAction)mySegmentsAct:(UISegmentedControl *)sender 
{ 
    switch (sender.selectedSegmentIndex) 
    { 
     case 0: 
      arrSelected = arrFirst; 
      break; 
     case 1: 
      arrSelected = arrSecond; 
      break; 
     case 2: 
      arrSelected = arrThird; 
      break; 
     case 3: 
      arrSelected = arrFourth; 
      break; 
     default: 
      arrSelected = nil; 
      break; 
    } 

    [myTableView reloadData]; 
} 

-(NSInteger)tableView:(UITableView *)tableView 
numberOfRowsInSection:(NSInteger)section 
{ 
    return [arrSelected 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 = (arrSelected)[indexPath.row]; 
    return cell; 
} 

Я мог бы также сделать это, используя один массив, а также путем первой промывки старое содержимое массива:
arrSelected = nil
, а затем положить новые элементы в этом массиве (из некоторого источника с использованием некоторой логики)
и, наконец:
myTableView reloadData.

+0

Спасибо, я пробовал ваше первое предложение, но не работал, он падает с неправильными номерами строк. – Tajuddin

0

Похоже, что когда вы выбрали второй сегмент и вышли из строя?
Таким образом, следующие коды вызывают ошибку.

[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete 
            withRowAnimation:UITableViewRowAnimationFade]; 

При использовании deleteRowsAtIndexPaths или insertRowAtIndexPaths, вы должны убедиться, длина источника данных совпадает с текущей строки Tableview.

Например: ваш tableView уже имеет 10 строк, теперь вам нужно удалить 2 строки, сначала вы должны удалить 2 объекта данных из своего массива данных, а затем вызвать deleteRowsAtIndexPaths.

+0

Я пробовал - (void) clearData { [self.tableView beginUpdates]; NSMutableArray * indexPathsToDelete = [[NSMutableArray alloc] init]; для (int i = [self.tableView numberOfRowsInSection: 0] - 1; i> = 0; i--) { [indexPathsToDelete addObject: [NSIndexPath indexPathForRow: i inSection: 0]]; NSLog (@ "Удалено:% d", i); } [self.tableView deleteRowsAtIndexPaths: indexPathsToDelete withRowAnimation: UITableViewRowAnimationFade]; [self.earthquakeList removeAllObjects]; [self.tableView endUpdates]; } – Tajuddin

+0

[self.earthquakeList removeAllObjects]; должен выполняться перед deleteRows ~~ – LeverkusenFan

0

Попробуйте эти замены, и дают нам некоторую обратную связь позже (особенно если NSAssert «разбился» приложение):

- (void)addEarthquakesToList:(NSArray *)earthquakes 
{ 
    // data checking 
    NSAssert(self.earthQuakeList != nil, @"earthQuakeList cannot be nil!"); 
    NSAssert(self.tableView != nil, @"tableView cannot be nil!"); 
    NSAssert(earthquakes != nil, @"earthquakes cannot be nil!"); 

    // relevant implementation 
    [self.earthquakeList addObjectsFromArray:earthquakes]; 
    [self.tableView reloadData]; 
} 

- (void)segmentedControlHasChangedValue 
{ 
    // data checking 
    NSAssert(self.earthQuakeList != nil, @"earthQuakeList cannot be nil!"); 
    NSAssert(self.tableView != nil, @"tableView cannot be nil!"); 
    NSAssert(fuelType != nil, @"fuelType cannot be nil!"); 
    NSAssert(locationManager != nil, @"locationManager cannot be nil!"); 

    // relevant implementation 
    switch (fuelType.selectedSegmentIndex) 
    { 
     case 0: 
      productName=1; // what is this? 
      [locationManager startUpdatingLocation]; 
      break; 

     case 1: 
      productName=2; 
      [self.earthquakeList removeAllObjects]; 
      [locationManager startUpdatingLocation]; 
      break; 

     case 2: 
      productName=4; 
      [locationManager startUpdatingLocation]; 
      break; 
     case 3: 
      productName=5; 
      [locationManager startUpdatingLocation]; 
      break; 

     default: 
      break; 
    } 

    [self.tableView reloadData]; // if you want to change the data whenever the user changes the UISegmentedControl to any new value, leave this here. 
} 

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
      fromLocation:(CLLocation *)oldLocation 
{ 
    // data checking 
    NSAssert(self.earthQuakeList != nil, @"earthQuakeList cannot be nil!"); 
    NSAssert(self.tableView != nil, @"tableView cannot be nil!"); 

    // relevant implementation 
    [self.earthquakeList removeAllObjects]; 
    [self.tableView reloadData]; 
} 
Смежные вопросы