简体   繁体   English

iOS:将新数据加载到UICollectionView

[英]ios: load new data into UICollectionView

I want to make a application which will display images into UICollectionView. 我想制作一个将图像显示到UICollectionView中的应用程序。

  • Images will be downloaded from server and then shows into collectionView. 图像将从服务器下载,然后显示到collectionView中。
  • I am using custom collectionView layout into xib file. 我正在使用自定义collectionView布局到xib文件中。
  • At a time, 20 images is receiving from server. 一次从服务器接收20张图像。

Problem: I can't show newly downloaded images into collectionView. 问题:我无法将新下载的图像显示到collectionView中。

Here is my code: 这是我的代码:

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

Any suggestion please? 有什么建议吗?

NOTE: I am just starting developing iOS application, this may be a very silly question. 注意:我刚刚开始开发iOS应用程序,这可能是一个非常愚蠢的问题。

Use asynchronously fetch to get data from server and display it in collectionView 使用异步获取从服务器获取数据并将其显示在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];
    }
}

Use a class to download the image. 使用课程下载图像。 If you have many images in one collection view, you may consider to save these images to local in case of memory warning. 如果一个集合视图中有很多图像,则在出现内存警告时,您可以考虑将这些图像保存到本地。 if now many, just leave the image in memory and display it in your collection view. 如果数量很多,只需将图像保留在内存中并在您的收藏夹视图中显示。

the code followed is save the image to local and read image data from local when displaying. 遵循的代码是将图像保存到本地,并在显示时从本地读取图像数据。

in .h: 在.h中:

#import <Foundation/Foundation.h>

@interface PortraitDownloader : NSObject

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

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

@end

in .m 在.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

if you want to leave your image in-memory, just modify the completion block as: 如果要将图像保留在内存中,只需将完成块修改为:

in .h 在.h中

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

@interface PortraitDownloader : NSObject

@property (nonatomic, copy) Completion_handle myCompletionBlock;

and in .m 并在.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);
    }
}

and also modify methods startDownloadImageForIndexPath, save the image to your model to retain it 并修改startDownloadImageForIndexPath方法,将图像保存到模型中以保留它

This method expects to have answers immediately: 该方法期望立即得到答案:

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

when your code doesn't respond fast enough to it, the app will usually display nothing, or sometimes just crash (depending on what you've setup) 当您的代码对它的响应速度不够快时,该应用通常将不显示任何内容,有时甚至崩溃(取决于您的设置)

A common design pattern is to store the info that will be supplied to the collectionView in a class variable (it doesn't have to be a property, but it often times is). 一种常见的设计模式是将要提供给collectionView的信息存储在类变量中(它不一定是属性,但通常是这样)。 You always store SOMETHING in that variable, even if it is old or stale data. 您始终将SOMETHING存储在该变量中,即使它是旧数据或陈旧数据也是如此。

Then you have the methods defined in the UICollectionViewDataSource protocol pull what they need directly from the class variables, with no delay. 然后,您可以在UICollectionViewDataSource协议中定义的方法无延迟地直接从类变量中提取所需的方法。

Other methods can fetch and retrieve and sling updated data around, and once they finish you call reloadData: on the collectionView to update the interface. 其他方法可以获取,检索和附加更新的数据,完成后,您可以在collectionView上调用reloadData:来更新接口。

assuming the asynchronous calls you are using are successfully retrieving data eventually, they are probably too slow for what the UICollectionViewDataSource protocol methods are expecting. 假设您使用的异步调用最终成功地检索了数据,那么对于UICollectionViewDataSource协议方法所期望的速度,它们可能太慢了。

A suggestion for how to get started would be to move the code fetching your data to separate methods, and then stage the data in a class variable or two which the collectionView can reliably draw from. 关于如何开始的建议是将获取数据的代码移动到单独的方法,然后将数据暂入collectionView可以可靠地提取的一两个类变量中。

You can try it with static data loaded into the bundle at first if you need, and then move into asynchronous pulls from the web too. 如果需要,您可以先将静态数据加载到捆绑软件中进行尝试,然后再从网络进行异步提取。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM