2014-12-13 6 views
1

Доброе утро,UICollectionView замерзает IOS приложение

Я использую UICollectionView впервые, чтобы показать изображения от пользователя (например, профиль Facebook) и на данный момент я могу показать изображения хорошо, но у меня есть некоторые проблемы:

1- Когда я нахожусь в моем профиле, приложение замерзает примерно на 2-3 минуты из-за загрузки 5 изображений.

2 Когда я перехожу через UICollectionView, он зависает, когда приложение снова загружает изображения за пределы экрана.

Что мне нужно сделать, чтобы не замораживать приложение при загрузке пользовательских изображений? И что мне нужно сделать, чтобы перемещаться по CollectionView без замерзания? Может быть, система кеш-то, что мне нужно?

Вот мой код:

ProfileViewController.m

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [self.view setBackgroundColor: [self colorWithHexString:@"FFFFFF"]]; 

    self.profileimage.layer.cornerRadius = self.profileimage.frame.size.width/2; 
    self.profileimage.clipsToBounds = YES; 
    self.profileimage.layer.borderWidth = 1.0f; 
    self.profileimage.layer.borderColor = [UIColor whiteColor].CGColor; 

    [self fetchJson]; 
    [self fetchImages]; 

    self.oneCollectionView.dataSource = self; 
    self.oneCollectionView.delegate = self; 
} 

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section 
{ 
    return 1; 
} 

-(NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView 
{ 
    return 1; 
} 

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 
{ 
    return _carImages.count; 
} 

// COLLECTION VIEW 
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
       cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    MyCollectionViewCell *myCell = [collectionView 
            dequeueReusableCellWithReuseIdentifier:@"MyCell" 
            forIndexPath:indexPath]; 

    NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"]; 
    NSURL * imageURL = [NSURL URLWithString:data]; 
    NSData * imageData = [NSData dataWithContentsOfURL:imageURL]; 
    UIImage * images = [UIImage imageWithData:imageData]; 

    myCell.imageview.image = images; 

    return myCell; 
} 

-(void)fetchImages { 

    self.carImages = [[NSMutableArray alloc] init]; 

    NSString *usersPassword = [SSKeychain passwordForService:@"login" account:@"account"]; 

    NSString * urlString = [NSString stringWithFormat:@"http://mywebsite.com/posts.php?usersPassword=%@",usersPassword]; 

    NSURL * url = [NSURL URLWithString:urlString]; 
    NSData * data = [NSData dataWithContentsOfURL:url]; 

    NSError *error; 
    [_jsonArray removeAllObjects]; 
    _jsonArray = [NSJSONSerialization 
        JSONObjectWithData:data 
        options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves 
        error:&error]; 

    for(int i=0;i<_jsonArray.count;i++) 
    { 
     NSDictionary * jsonObject = [_jsonArray objectAtIndex:i]; 
     NSString* imagen = [jsonObject objectForKey:@"imagen"]; 
     [_carImages addObject:imagen]; 
    } 
} 

Спасибо заранее.

+0

Вы используете фактическое изображение (с большим размером) ИЛИ вы сделали эскизы (с очень маленьким размером foo, отображаемым в 'UICollectioViewCell')? – Anon

+0

Я использую фактическое изображение и внутри изображения, я просто говорю ширину и высоту. –

ответ

0

Вы можете использовать диспетчер для создания асинхронной операции для загрузки изображений. Это позволит решить 2 проблемы у вас есть:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    NSData *imgData = [NSData dataWithContentsOfURL:YOUR_IMAGE_URL]; 
    UIImage *img = [UIImage imageWithData:imgData]; 
    [YOUR_IMAGE_VIEW_OUTLET performSelectorOnMainThread:@selector(setImage:) withObject:img waitUntilDone:YES]; 
}); 

Это фрагмент кода, вы должны изменить:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
      cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    MyCollectionViewCell *myCell = [collectionView 
           dequeueReusableCellWithReuseIdentifier:@"MyCell" 
           forIndexPath:indexPath]; 

    NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"]; 
    NSURL * imageURL = [NSURL URLWithString:data]; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     NSData *imageData = [NSData dataWithContentsOfURL: imageURL]; 
     UIImage *img = [UIImage imageWithData:imageData]; 
     [myCell.imageview performSelectorOnMainThread:@selector(setImage:) withObject:img waitUntilDone:YES]; 
    }); 

    return myCell; 
} 
+0

Спасибо @LucaD, где я должен поставить этот код? Очень признателен. –

+0

Если вы используете код + (NSData *) dataWithContentsOfURL: (NSURL *) url –

+0

Когда я использую ваш код @LucaD, проблемы разрешаются, но на данный момент у меня есть еще один: изображения не отображаются до 3-5 секунд и то я могу перемещаться по ним без проблем, но кажется, что для загрузки изображений требуется столько времени. –

0

Попробуйте Регистрацию СИБА Для Collection Посмотреть

Написать следующий код в viewDidLoad() методы вашего ViewController в:

UINib *nib = [UINib nibWithNibName:@"MyCollectionCell" bundle: nil]; 
[self.collectionView registerNib:nib forCellWithReuseIdentifier:@"Cell"]; 

И я думаю, что вы должны использовать https://github.com/nicklockwood/AsyncImageView для загрузки изображений в целях сбора.

Для раскадровки вы должны увидеть этот урок: http://www.appcoda.com/ios-programming-uicollectionview-tutorial/ Это поможет вам больше.

Спасибо!

+0

Спасибо @Ashish, но где я должен написать этот код? –

+0

см. Обновленный ответ. @ Thomas_12 Добро пожаловать :) –

+0

Спасибо @Ashish, но он показывает мне, что ошибка: Не удалось загрузить NIB в комплекте. Это потому, что я использую раскадровку? –

0

Для первого вопроса, ответ находится в этой строке кода:

NSData * data = [NSData dataWithContentsOfURL:url]; 

От Apple Reference:

Do not use this synchronous method to request network-based URLs. For network-based URLs, this method can block the current thread for tens of seconds on a slow network, resulting in a poor user experience, and in iOS, may cause your app to be terminated.

качестве альтернативы вы можете использовать NSURLSessionDataTask для загрузки данных (см Apple Reference)

-Edit

В ProfileViewController.h добавить эти два свойства:

@property (nonatomic, strong) NSURLSessionConfiguration *sessionConfig; 
@property (nonatomic, strong) NSURLSession *session; 

затем, в - viewDidLoad инициализирует их:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view 
    self.sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; 
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfig]; 
    //Other stuff... 
} 

Наконец, в ProfileViewController.m

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
       cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    MyCollectionViewCell *myCell = [collectionView 
            dequeueReusableCellWithReuseIdentifier:@"MyCell" 
            forIndexPath:indexPath]; 

    NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"]; 
    NSURL * imageURL = [NSURL URLWithString:data]; 
    NSURLSessionDownloadTask *imageDownloadTask = [self.session dataTaskWithURL:imageURL 
             completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
              if (error) { 
               NSLog(@"ERROR: %@", error); 
              } else { 

               NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 
               if (httpResponse.statusCode == 200) { 
                UIImage *image = [UIImage imageWithData:data]; 

                 myCell.imageview.alpha = 0.0f; 
                 myCell.imageview.image = image; 
                 [UIView animateWithDuration:0.45 animations:^{ 
                  myCell.imageview.alpha = 1.0f; 
                }); 
               } else { 
                NSLog(@"Couldn't load image at URL: %@", imageURL); 
                NSLog(@"HTTP %d", (int)httpResponse.statusCode); 
               } 
              } 
             }]; 
    [imageDownloadTask resume]; 

    return myCell; 

} 

Я надеюсь, что это может помочь тебе.

- Edit 2 Для будущих читателей, я немного переработан мой код, основанный на ответ @ suhit в (+1 для него)

+0

Почему вы используете этот материал, когда можете использовать НОД? Возможно, лучше, если вы используете диспетчер для создания асинхронной операции. –

+0

@LucaD «этот материал» - это именно то, что создал Apple для выполнения такого рода задач. _ Класс NSURLSession и связанные классы предоставляют API для загрузки содержимого через HTTP. Этот API предоставляет богатый набор методов делегатов ...._ [link] (https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html). Во всяком случае, мой фрагмент не хотел быть идеальным, но полезным ответом, что вы можете реорганизовать, как вам нравится, если хотите. – bl4stwave

1

Загрузить изображения асинхронно, dataWithContentsOfURL синхронный метод, и он будет блокировать ваш текущий поток пока загрузка не завершится. Вы можете использовать библиотеки, такие как SDWebImage, чтобы автоматически обрабатывать скачивание для вас или вы можете использовать NSURLSessionDownloadTask для загрузки изображений.

- (void)fetchImages { 

    self.carImages = [[NSMutableArray alloc] init]; 

    NSString *usersPassword = [SSKeychain passwordForService:@"login" account:@"account"]; 

    NSString * urlString = [NSString stringWithFormat:@"http://mywebsite.com/posts.php?usersPassword=%@",usersPassword]; 

    NSURL * url = [NSURL URLWithString:urlString]; 

    NSURLSession *session = [NSURLSession sharedSession]; 
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     if (!error) { 

      [self.jsonArray removeAllObjects]; 
      self.jsonArray = [NSJSONSerialization 
           JSONObjectWithData:data 
           options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves 
           error:&error]; 

      for(int i=0;i<_jsonArray.count;i++) 
      { 
       NSDictionary * jsonObject = self.jsonArray[i]; 
       NSString* imagen = jsonObject[@"imagen"]; 
       [self.carImages addObject:imagen]; 
      } 
     } 

    }]; 
    [dataTask resume]; 

} 

// COLLECTION VIEW 

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
    cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    MyCollectionViewCell *myCell = [collectionView 
            dequeueReusableCellWithReuseIdentifier:@"MyCell" 
            forIndexPath:indexPath]; 

    NSString *data = [[self.jsonArray objectAtIndex:indexPath.row] valueForKey:@"imagen"]; 
    NSURL * imageURL = [NSURL URLWithString:data]; 

    NSURLSessionDownloadTask *imageDownloadTask = [[NSURLSession sharedSession] 
    downloadTaskWithURL:imageURL completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { 
     UIImage *image = [UIImage imageWithData: 
     [NSData dataWithContentsOfURL:location]]; 
     myCell.imageview.image = image; 
    }]; 

    [imageDownloadTask resume]; 

    return myCell; 
} 
1

Импорт UIImageView+AFNetworking.h

и загрузить изображение с помощью этого метода в cellForItemAtIndexPath методом

[imageView setImageWithURL:[NSURL URLWithString:@"https://lh6.googleusercontent.com/-B8kSXtoaQDo/VGTVlXyIXpI/AAAAAAAAJ_M/USh6SgvMemw/w1024-h1024/IMG_20141112_103152.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]]; 

это, безусловно, ускорит загрузку и прокрутка collectionView

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