2014-02-21 3 views
1

Я занимаюсь разработкой iPhone приложение, в котором я скачиваю файл с сервера в фоновом режиме,Tableview скроллинг врезается приложение

Вот вид моего приложения,

, когда я нажимаю на Button 1 я выборка 5 данных от сервера также изображения, после получения данных, когда пользователь прокручивается, я снова получаю новые 5 данных с сервера, когда пользователь прокручивает вверх, я получаю новые 5 данных с сервера и так далее.

при выборке данных для Button 1 если я нажимаю на Button 2 я отменяя мою предыдущую нить Button 1 и я извлечение новых данных 5 для Button 2 и прокрутки снова получении новых данных 5 То же, что кнопка 1

но через некоторое время перезагрузки TableView мое приложение получает сбои и шоу: , истекающие приложение из-за неперехваченное исключение 'NSRangeException', причина: '- [__ NSArrayM objectAtIndex]: индекс 28 за пределами [0 .. 4]

Это мой фрагмент кода:

- (void)viewDidLoad 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     [self fetchDataForButton1]; 

     dispatch_async(dispatch_get_main_queue(), ^(void) { 


       [tableView reloadData]; 


     }); 
    }); 

} 


- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath 
{ 
if(it is last row then fetch new 5 data) 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

         //Code runs on background thread 
         [self LoadMoreData]; 

         dispatch_async(dispatch_get_main_queue(), ^(void) { 

          //Code here is run on the main thread 
          [_tblList reloadData]; 

         }); 
        }); 


     }else{ 
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

           [self beginBackgroundFetchTask]; 

           [self downloadImage_3:indexPath]; 

           [self endBackgroundFetchTask]; 
          }); 
     } 

} 


-(void)downloadImage_3:(NSIndexPath *)path{ 


     UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:ImagePath]]]; 

     if (img) { 
      [dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"Merchant_SmallImage"]]; 
     } 

     [_tblList performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 


} 

- (void) beginBackgroundFetchTask 
{ 
    self.backgroundFetchTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     [self endBackgroundFetchTask]; 
    }]; 
} 

- (void) endBackgroundFetchTask 
{ 
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundFetchTask]; 
    self.backgroundFetchTask = UIBackgroundTaskInvalid; 
    NSLog(@"ended BackgroundFetchTask"); 
} 

-(void)LoadMoreData 
{ 
    //Fetches new 5 data from server... 
} 
+0

попробовать отладки приложения, поставить точку останова на cellForRowAtIndexPath. См., Когда массив выходит за пределы. Ошибка, которую вы получаете, состоит в том, что массив получает значение null для определенного indexPath.row. – z22

+0

** Причина: [__NSArrayM objectAtIndex:]: индекс 28 за пределами границ [0 .. 4] **, вы пытаетесь получить доступ к объекту с индексом 28, но ваш массив имеет всего 5 элементов. – iNoob

+0

Вы - правильный чувак, но когда я нажимаю на 'Button 2' я остановил выборку данных' Button 1', и я инициализирую свой массив и снова получаю новые данные для 'Button 2', но происходит сбой, потому что он все еще извлекает данные индекса' Button 1' ** 28 ** имеет «Button 1», как я должен остановить мой поток «Button 1»? при нажатии кнопки «2» – Krunal

ответ

1

Я думаю, что проблема может быть в [self downloadImage_3:indexPath]; вы называете dispatch_async, когда вы на Button1 и dispatch_async блок не вызывается, то вы нажимаете на Button2, то я думаю, msg_array очищается и наполняется новым 5 объекта, после того, dispatch_async блок вызывается, то path.row для блока составляет 28, тогда как msg_array имеет новое содержимое массива с 5 новыми объектами, а затем сбой.

Вы должны отменить dispatch_async Перед нажатием на другую кнопку, что невозможно для dispatch_async, так что вы можете иметь суждение в блоке:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    [self beginBackgroundFetchTask]; 

    [self downloadImage_3:indexPath buttonIndex:index]; 

    [self endBackgroundFetchTask]; 
}); 

-(void)downloadImage_3:(NSIndexPath *)path buttonIndex:(int)buttonIndex{ 
    if(self.currentSelectIndex != buttonIndex) return; //skip reloadData if not same index 


     UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:ImagePath]]]; 

     if (img) { 
      [dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"Merchant_SmallImage"]]; 
     } 

     [_tblList performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 

} 
+0

Да, чувак, вы очень правы, то же самое происходит здесь. – Krunal

+0

Но проблема в том, что 'downloadImage_3' вызывается для каждой ячейки, если я пропускаю для того же индекса, то как я возьму изображение для того же индекса при прокрутке? – Krunal

+0

@ Krunal. Как я комментирую, пропустите reloadData, если не тот же индекс, вам нужно только обновлять данные о помощи, пока данные влияют на текущее выбранное представление. – simalone

0

Используйте SDWebImage для извлечения изображений с сервера.

+0

Вы правы чувак, но когда я нажимаю кнопку 'Button 2', я прекратил получать данные из' Button 1', и я инициализирую свой массив и снова получаю новые данные для 'Button 2', но происходит сбой, потому что он все еще извлекает данные из' Button 1' index ** 28 ** имеет значение 'Button 1', как я должен остановить мой поток' Button 1'? при нажатии кнопки 'Button 2' – Krunal

0

AS на ваш массив журналов имеет только 5 счетчиков, и вы извлекаете данные в соответствии с indexpath.row, и в этом случае сбой . Поэтому может быть, что вы корректируете строку индекса ячейки в соответствии с вашим новым массивом, который снова и снова извлекает данные при прокрутке, но в повторении .

Просто поместите контрольную точку и проверьте, не сбросили ли строку индексного пути в [0 4];

ОБНОВЛЕНО:

[[NSThread currentThread] populateDataInBackground]; 
+0

Вы правильный чувак, но когда я нажимаю кнопку' Button 2', я прекратил выборку данные 'Button 1', и я инициализирую свой массив и снова получаю новые данные для' Button 2', но сбой происходит, потому что он все еще извлекает данные индекса 'Button 1' ** 28 ** из' Button 1', как следует остановить мой поток 'Button 1'? при нажатии кнопки' 2' – Krunal

0

Это происходит потому, что изображения потребуется время для загрузки с сервера и ячейки не получает данные, когда она выделяется.

Для этого вам необходимо выполнить ленивую загрузку.

Here - хороший учебник.

+0

Вы - правильный чувак, но когда я нажимаю кнопку 'Button 2', я перестал извлекать данные из' Button 1', и я инициализирую свой массив и снова получаю новые данные для 'Button 2', но сбой происходит, потому что он все еще выбирает данные индекса 'Button 1' ** 28 ** относятся к' Button 1', как я должен остановить мой поток 'Button 1'? при щелчке кнопки 'Button 2' – Krunal

0

Отключить взаимодействие с пользователем затем перейти к началу на столе:

[TableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; 

тогда звоните:

[TableView reloadData]; 

включите userintercation. надежды решить проблему

+0

Вы правы, но когда я нажимаю кнопку' Button 2', я перестал извлекать данные из 'Button 1', и я инициализирую свой массив и снова получаю новые данные для' Button 2', но сбой происходит потому, что он все еще извлекает данные индекса 'Button 1' ** 28 ** из' Button 1', как я должен остановить мой поток 'Button 1'? при щелчке кнопки 'Button 2' – Krunal

1

Попробовать это

1) Используйте SDWebImage для извлечения изображений с сервера

2) Используйте Pull Refresher функции для извлечения следующих 5 данных.

Это поможет получить данные в фоновом режиме.

+0

Вы - правильный чувак, но когда я нажимаю кнопку' Button 2', я прекратил получать данные из 'Button 1', и я инициализирую свой массив и снова получаю новые данные для' Button 2', но сбой происходит потому, что он все еще извлекает данные индекса 'Button 1' ** 28 ** из' Button 1', как я должен остановить мой поток 'Button 1'? при нажатии кнопки «2» – Krunal

+0

Чтобы остановить поток, обратитесь к этому: http://stackoverflow.com/questions/11553863/objective-c-canceling-a-thread – Siddh

0

Я бы не получил данные, подобные этому из метода cellForRowAtIndexPath. Это используется для отображения ячеек.

Вместо сделать это следующим образом:

  1. Перечислите исходные данные.
  2. Когда пользователь прокручивает последнюю ячейку, отобразите нижний колонтитул, который отображает символ загрузки.
  3. одновременно Хотя сноска отображает символ загрузки, а затем и только затем вызвать метод fetchLoadData и WAIT
  4. Пока вы не слышите от сервера, по-прежнему отображать символ загрузки, то не начать добавлять новые клетки приготовьтесь к чему-либо, потому что, скорее всего, вы можете либо не получить больше данных назад, что в этот момент вам нужно избавиться от нижнего колонтитула и сообщить пользователю, что больше нет данных для извлечения, или если есть больше данных для display, THEN настройте следующие 5 ячеек, выполнив следующие действия:
    • , добавив в ваш массив данных 5 новых объектов данных
    • обновление номера строки в секции с использованием методы numberOfRowsInSection делегата
    • Вы обнаружите, что ваши клетки, если закодированные правильно будет отображаться правильно, как только вы обновите таблицу с помощью [myTable reloadTable];
Смежные вопросы