2015-06-15 2 views
1

Я столкнулся с какой-то странной проблемой. Один из моих NSURLSessions отвечает за получение информации для информации о ресторанах, которую я сохранил (название ресторана, URL логотипа ресторана и т. Д.), А затем второй NSURLSession отвечает за использование URL логотипа ресторана, чтобы получить конкретное изображение и установить его для каждой ячейки UITableView.Несколько NSURLSessions, вызывающие проблемы UITableView

Проблема заключается в том, что мой UITableView вообще не загружает ничего, поэтому ячейки пустые, но в другое время, когда я добавляю дополнительный [_tableView reload] в блок завершения NSURLSessions в методе fetchPosts, он будет но затем ячейки перестанут отображать что-либо снова, если я снова запустил его. Что-то определенно неправильно. Посмотрите на мой код ниже:

#import "MainViewController.h" 
#import "SWRevealViewController.h" 
#import "RestaurantNameViewCell.h" 
#import "RestaurantList.h" 

@interface MainViewController() 

@end 

@implementation MainViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 


    //List of restaurants needed to load home page 
    _restaurantInformationArray = [[NSMutableArray alloc] init]; 


    self.tableView.dataSource = self; 
    self.tableView.delegate = self; 


    //setup for sidebar 
    SWRevealViewController *revealViewController = self.revealViewController; 
    if (revealViewController) 
    { 
     [self.sidebarButton setTarget: self.revealViewController]; 
     [self.sidebarButton setAction: @selector(revealToggle:)]; 
     [self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer]; 
    } 



    //Get list of restaurants and their image URLs 
    [self fetchPosts]; 

} 

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


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

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return [_restaurantInformationArray count]; 
} 

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    RestaurantNameViewCell *cell = (RestaurantNameViewCell *)[_tableView dequeueReusableCellWithIdentifier:@"restaurantName" forIndexPath:indexPath]; 

    RestaurantList *currentRestaurant = [_restaurantInformationArray objectAtIndex:indexPath.row]; 


    cell.restaurantName.text = currentRestaurant.name; 
    cell.imageAddress = currentRestaurant.imageURL; 

    cell.restaurantClicked = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapDetected:)]; 
    cell.restaurantClicked.numberOfTapsRequired = 1; 
    cell.restaurantLogo.userInteractionEnabled = YES; 
    [cell.restaurantLogo addGestureRecognizer:cell.restaurantClicked]; 
    cell.restaurantLogo.tag = indexPath.row; 

    //Add restaurant logo image: 
    NSString *URL = [NSString stringWithFormat:@"http://private.com/images/%@.png",cell.imageAddress]; 
    NSURL *url = [NSURL URLWithString:URL]; 

    NSURLSessionDownloadTask *downloadLogo = [[NSURLSession sharedSession]downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { 
     UIImage *downloadedImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:location]]; 

     cell.restaurantLogo.image = downloadedImage; 
    }]; 
    [downloadLogo resume]; 

    return cell; 
} 



-(void)fetchPosts { 
    NSString *address = @"http://localhost/xampp/restaurants.php"; 
    NSURL *url = [NSURL URLWithString:address]; 

    NSURLSessionDataTask *downloadRestaurants = [[NSURLSession sharedSession]dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 

     NSError *someError; 
     NSArray *restaurantInfo = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&someError]; 


     for(NSDictionary *dict in restaurantInfo) { 
      RestaurantList *newRestaurant = [[RestaurantList alloc]init]; 

      newRestaurant.name = [dict valueForKey:@"name"]; 
      newRestaurant.imageURL = [dict valueForKey:@"image"]; 

      [_restaurantInformationArray addObject:newRestaurant]; 


      //Refresh table view to make sure the cells have info AFTER the above stuff is done 
      [_tableView reloadData]; 
     } 
    }]; 

    [downloadRestaurants resume]; 
} 


@end 

Это, наверное, очень глупая ошибка, что я делаю, но я не уверен, как я должен это исправить. Я новичок в разработке iOS, поэтому очень ценю некоторые рекомендации :)

+0

Что вы подразумеваете под словом «он снова останавливается, если я его заново заново»? Вы имели в виду, что он не приносит результатов, если вы повторно запускаете свое приложение? – Jeff

+0

@Jeff Как и клетки, ничего не будет отображаться. – pwoerfulafhjksdh

+0

@Jeff, что вы думаете? – pwoerfulafhjksdh

ответ

3

Кроме того, если ваши сетевые запросы не являются ошибками (вы должны хотя бы регистрировать, если есть сетевые ошибки), возникают проблемы с потоками.

Обратный вызов NSURLSession, вероятно, работает на фоне потока. Это делает небезопасным вызов UIKit (aka - [_tableView reloadData]). UIKit не является потокобезопасным. Это означает, что вызов любого из API UIKit из другого потока создает недетерминированное поведение. Вы хотите, чтобы запустить этот кусок кода на главной теме:

dispatch_async(dispatch_get_main_queue(), ^{ 
    [_tableView reloadData]; 
}); 

Аналогично для извлечения изображений. Это немного сложнее из-за повторного использования ячеек таблицы, которые могут привести к неправильному отображению изображения при прокрутке. Это связано с тем, что один и тот же экземпляр ячейки используется для нескольких значений в вашем массиве, когда пользователь прокручивает. Когда какой-либо из этих обратных вызовов срабатывает, он заменит любое изображение, находящееся в этой ячейке. В целом шаги, чтобы воспроизвести это выглядит следующим образом:

  1. TableView просит 5 клеток
  2. MainViewController запрашивает 5 изображений (по одному для каждой ячейки)
  3. прокрутки вниз одну ячейки
  4. Первой ячейка получает повторно используются в качестве 6-я ячейка.
  5. MainViewController запрашивает другое изображение для 6-й ячейки.
  6. Получено 6-е изображение, обратный вызов запускается, изображение первой ячейки установлено на изображение # 6.
  7. Получено 1-е изображение, обратный вызов запускается, изображение первой ячейки установлено на изображение # 1 (неверно).

Прежде чем пытаться назначить изображение, вам необходимо убедиться, что ячейка отображает правильную ячейку. Если вы предпочитаете не реализовывать эту логику для извлечения изображений в ячейках, вместо этого вы можете использовать SDWebImage. Использование SDWebImage [UIImageView sd_setImageWithURL:] является потокобезопасным (оно будет set the image on the main thread).

Боковые ноты:

  • Вам только нужно перезагрузить данные, когда все ваши изменения в _restaurantInformationArray, а не каждый раз в течение цикла.
+0

Когда мы используем SDWebImage для tableviewcells, мне нужно приложить его к блокам отправки Grand Central? Или все это уже обработано? – pwoerfulafhjksdh

+0

Это потокобезопасно, если вы используете расширения UIImageView от SDWebImage: https://github.com/rs/SDWebImage/blob/master/SDWebImage/UIImageView+WebCache.m#L55-L70 – Jeff

Смежные вопросы