ios:将新数据加载到UICollectionView

我想做一个应用程序,将图像显示到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; } 

有什么build议吗?

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

使用asynchronous获取从服务器获取数据并将其显示在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]; } } 

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

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

在.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; 

和.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,将图像保存到模型中以保留它

此方法预计立即有答案:

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

当你的代码没有足够快的响应,应用程序通常不会显示任何内容,或者有时只是崩溃(取决于你设置的内容)

一个常见的devise模式是将要提供给collectionView的信息存储在一个类variables中(它不一定是属性,但通常是这样)。 即使数据是旧的或陈旧的数据,您也总是将SOMETHING存储在该variables中。

然后你有在UICollectionViewDataSource协议中定义的方法直接从类variables中拉出他们所需要的东西,而没有任何延迟。

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

假设您正在使用的asynchronous调用最终正在成功检索数据,那么对于UICollectionViewDataSource协议方法所期望的,它们可能太慢。

关于如何开始的build议是将获取数据的代码移动到单独的方法中,然后将数据放在一个或两个collectionView可以可靠地从中抽取的类variables中。

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

 - (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; }