2013-10-24 50 views
2

我想制作一个将图像显示到UICollectionView中的应用程序。ios:将新数据加载到UICollectionView中

  • 图像将从服务器下载,然后显示为collectionView。
  • 我正在使用自定义collectionView布局到xib文件中。
  • 一次,从服务器接收20个图像。

问题:我不能显示新下载的图像转换成的CollectionView。

这里是我的代码:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 

    BOOL reloaded = NO; 

    static NSString *cellIdentifier = @"cvCell"; 

    CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; 

    NSMutableArray *data = [self.dataArray objectAtIndex:indexPath.section]; 

    NSString *cellData = [data objectAtIndex:indexPath.row]; 

    dispatch_queue_t queue = dispatch_queue_create("com.justTest.anotherSingleApplication", NULL); 
    dispatch_async(queue, ^{ 
     //code to be executed in the background 
     NSString *imageName1 = [[NSString alloc]initWithFormat:@"http://www.abc.com/images/thumb/%@", cellData]; 
     NSString *url_Img1 = imageName1; 
     UIImage *aImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url_Img1]]]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      //code to be executed on the main thread when background task is finished 
      [cell.cellImage setImage:aImage]; 

     }); 
    }); 

    if (indexPath.row == self.imageArray.count - 1 && !reloaded) { 

     getOnScrollImages *getImage = [[getOnScrollImages alloc] init]; // class to get image name from server 
     NSMutableArray *astring = (NSMutableArray *)[getImage getImageNameFromServer:@"list" board:@"111" pin:@"122345"]; // method to get image name from server 

     [self setNewTestArray:astring]; //adding newly downloaded image name into array 

     reloaded = YES; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self.collectionView reloadData]; 
     }); 
    } 

    return cell; 
} 

任何建议吗?

注:我刚开始开发iOS应用程序,这可能是一个非常愚蠢的问题。

回答

2

使用异步读取从服务器获取数据,并在的CollectionView

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    YourDataModel *model = self.dataArray[indexPath.row];  
    YourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; 

    if ([self checkWhetherImageAlreadyExist]) { 

     [cell.imageView setImage:model.image]; 

    } else { 
     //show placeholder to avoid nothing in your UI, or your user gets confused 
     [cell.imageView setImage:placeholderImage]; 
     [self startDownloadImageForIndexPath:indexPath]; 
    } 
} 

- (void)startDownloadImageForIndexPath:(NSIndexPath *)indexPath 
{ 
    //YourImageDownloader is a class to fetch data from server 
    //imageDownloadsInProgress is a NSMutableDictionary to record the download process, which can avoid repeat download 
    YourImageDownloader *downloader = [self.imageDownloadsInProgress objectForKey:indexPath]; 

    if (downloader == nil) { 
     YourDataModel *model = self.dataArray[indexPath.row]; 

     //configure downloader 
     downloader = [[YourImageDownloader alloc] init]; 
     [downloader setURL:model.url]; 
     [downloader setCompletionHandler:^{ 
      //download the image to local, or you can pass the image to the block 
      model.image = [UIImage imageWithContentsOfFile:model.localPath]; 
      YourCell *cell = [self.mCollectionView cellForItemAtIndexPath:indexPath]; 
      [cell.imageView setImage:model.image]; 

      //remove downloader from dictionary 
      [self.imageDownloadsInProgress removeObjectForKey:indexPath]; 
     }]; 

     //add downloader to dictionary 
     [self.imageDownloadsInProgress setObject:downloader forKey:indexPath]; 

     //start download 
     [downloader startDownload]; 
    } 
} 

显示它使用一个类来下载图像。如果您在一个集合视图中有多个图像,则可能会考虑将这些图像保存到本地以防内存警告。如果现在很多,只需将图像留在内存中并将其显示在收藏视图中。

接下来的代码是将图像保存到本地,并在显示时从本地读取图像数据。

in。H:

#import <Foundation/Foundation.h> 

@interface PortraitDownloader : NSObject 

@property (nonatomic, copy) NSString *portraitName; 
@property (nonatomic, copy) void (^completionHandler)(void); 

- (void)startDownload; 
- (void)cancelDownload; 

@end 

在.M

#import "PortraitDownloader.h" 
#import <CFNetwork/CFNetwork.h> 
#import "NSString+ImagePath.h" // it's a category to get the image local path 

@interface PortraitDownloader() 

@property (nonatomic, strong) NSMutableData *activeDownload; 
@property (nonatomic, strong) NSURLConnection *portraitConnection; 

@end 

@implementation PortraitDownloader 

- (void)startDownload 
{ 
    self.activeDownload = [NSMutableData data]; 

    NSString *urlstr = [NSString serverPortraitPathWithPortrait:self.portraitName]; 
    NSURL *url = [NSURL URLWithString:urlstr]; 
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 

    self.portraitConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
} 

- (void)cancelDownload 
{ 
    [self.portraitConnection cancel]; 
    self.portraitConnection = nil; 
    self.activeDownload = nil; 
} 

#pragma mark - NSURLConnectionDelegate 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    [self.activeDownload appendData:data]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    // Clear the activeDownload property to allow later attempts 
    self.activeDownload = nil; 

    // Release the connection now that it's finished 
    self.portraitConnection = nil; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    // save to local path 
    NSString *localSavePath = [NSString localPortraitPathWithPortrait:self.portraitName]; 
    [self.activeDownload writeToFile:localSavePath atomically:YES]; 

    self.activeDownload = nil; 

    // Release the connection now that it's finished 
    self.portraitConnection = nil; 

    // call our delegate and tell it that our icon is ready for display 
    if (self.completionHandler) { 
     self.completionHandler(); 
    } 
} 

@end 

如果你想留在内存中的图像,只修改完成块为:

在.H

typedef void (^Completion_handle) (UIImage *image); 

@interface PortraitDownloader : NSObject 

@property (nonatomic, copy) Completion_handle myCompletionBlock; 

and in .m

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    // get image from data 
    UIImage *image = [UIImage imageWithData:self.activeDownload]; 

    self.activeDownload = nil; 

    // Release the connection now that it's finished 
    self.portraitConnection = nil; 

    // call our delegate and tell it that our icon is ready for display 
    if (self.myCompletionBlock) { 
     self.myCompletionBlock(image); 
    } 
} 

,并修改方法startDownloadImageForIndexPath,将图像保存到你的模型把它保留下来

+0

感谢您的工作。它帮助我很多。 – Mehdi

0
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath]; 
UIImageView *imgView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"profile_pic.png"]]; 
NSMutableDictionary *contactData=[NSMutableDictionary new]; 
contactData = [self.collectionData objectAtIndex:indexPath.row]; 
imgView.image=[contactData objectForKey:@"image"]; 
[cell addSubview:imgView]; 
return cell; 
} 
1

这个方法只需要马上有答案:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 

当你的代码没有足够快的响应它,应用程序通常会显示什么都没有,有的干脆崩溃(这取决于你“已经建立)

一个常见的设计模式是用于存储将在一个类变量被提供给的CollectionView(它不必须是一个属性的信息,但它往往是倍)。您始终将SOMETHING存储在该变量中,即使它是旧的或陈旧的数据。

然后,你必须在UICollectionViewDataSource协议中定义的方法拉什么,他们需要直接从类变量,没有延迟。

其他方法可以获取并检索并索引更新的数据,一旦完成,您可以在collectionView上调用reloadData:来更新接口。

假设你使用的最终成功地检索数据的异步调用,他们很可能是为了什么UICollectionViewDataSource协议方法期待太慢。

一种如何开始将是一个类变量或两个其中的CollectionView能够可靠地借鉴移动代码获取你的数据不同的方法,然后阶段数据的建议。

如果需要的话,您可以首先使用加载到包中的静态数据进行尝试,然后再从网络进入异步提取。

+0

有必然是大量的实例各地从模式,但如果你愿意,你可以[看看我的一个项目](https://github.com/ryancumley/FilterChain)我使用这种模式。 FilterBank类将内容存储在名为_displayFilters的变量中,该变量会在应用程序中定期更新。 collectionView然后根据需要直接从_displayFilters中绘制。 –

+0

雅,它什么也没有显示,有时也会在新数据到达时崩溃。所以,你建议我先获取所有图像,然后将这些图像传递给UICollectionView?但是,如果有超过500张图片?它会不会花费很长时间加载数据? – Mehdi

+1

您不必一次加载500张图像。只需加载一个图像并设置完成块或委托。当服务器抓取完成时,将图像设置为您的单元格 – Jing

相关问题