在UICollectionView如何预加载数据以外的cellForItemAtIndexPath在其中使用? [英] In a UICollectionView how can I preload data outside of the cellForItemAtIndexPath to use within it?

查看:1032
本文介绍了在UICollectionView如何预加载数据以外的cellForItemAtIndexPath在其中使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象出缓慢加载的图像是我的collectionView的波纹的慢效果的背后。
我一直在阅读不同的Q& A的一整天和各种论坛帖子。看起来像解决这个问题的最好的方法是使数据预加载可用于cellForItemAtIndexPath能够采取它所需要的。



我不知道我该怎么做。我使用解析作为我的后端,但确保如果给了一个粗略的例子,我能够找出如何做到。从现在我所见到的,我需要一个单独的方法来抓取数据。



这里是代码: b
$ b

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


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [[self objects] count ];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
NSArray * people = [self objects];
static NSString * CellIdentifier = @Cell;

VAGGarmentCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];


PFObject * current;

current = [people objectAtIndex:indexPath.item];

PFFile * userImageFile = current [@image];

[userImageFile getDataInBackgroundWithBlock:^(NSData * imageData,NSError * error){
UIImage * image = [UIImage imageWithData:imageData];

[[cell contentView] setContentMode:UIViewContentModeScaleAspectFit];
[[cell imageView] setImage:image];

}];

[[cell title] setText:[current valueForKey:@title]];
[[cell price] setText:[NSString stringWithFormat:@£%@,[current valueForKey:@price]]];

return cell;

}

所以也许cellForItemAtIndexPath需要调用该方法,它需要。因为数据已经可用,所以不需要在cellForItemAtIndexPath方法中加载,并且会立即填充这些单元格。



请提供建议和示例。 p>

我被告知一个好的方法是检查图像,如果不存在提供一个占位符,如果它存在设置它。以下是对上述代码的更改。



更新

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

NSArray * people = [自我]

static NSString * CellIdentifier = @Cell;

VAGGarmentCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];



PFObject * current;

current = [people objectAtIndex:indexPath.item];



PFFile * userImageFile = current [@image];

[userImageFile getDataInBackgroundWithBlock:^(NSData * imageData,NSError * error){

if(!error)
{

if (!image){
[[cell imageView] setImage:[UIImage imageNamed:@placeholder.png]];


} else {

image = [UIImage imageWithData:imageData];


// resize image
CGSize destinationSize = CGSizeMake(158,187);
UIGraphicsBeginImageContext(destinationSize);
[image drawInRect:CGRectMake(0,0,destinationSize.width,destinationSize.height)];

//新图片
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

//优化图像
NSData * imageDataCompressed = UIImageJPEGRepresentation(newImage,0.4f);
// NSLog(@%@,[current sizeForKey:@title)NSLog(@%@,NSStringFromCGSize(newImage.size) ]);


[[cell imageView] setImage:[UIImage imageWithData:imageDataCompressed]];



}

}

}];


[[cell title] setText:[current valueForKey:@title]];
[[cell price] setText:[NSString stringWithFormat:@£%@,[current valueForKey:@price]]];


return cell;

}

占位符显示正常,但保留,图片已加载,所以我可以让我的单元格反映这一点?



感谢您的时间。



 

code> - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{

NSArray * people =对象]

static NSString * CellIdentifier = @Cell;

VAGGarmentCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];

[cell.activityIndi​​cator startAnimating];

PFObject * current;

current = [people objectAtIndex:indexPath.item];



PFFile * userImageFile = current [@image];

NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:userImageFile.url,indexPath.item]];
NSURLRequest * urlRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataDontLoad
timeoutInterval:6.0];
[cell.imageView setImageWithURLRequest:urlRequest
placeholderImage:[UIImage imageNamed:@placeholder.png]
success:^(NSURLRequest * request,NSHTTPURLResponse * response,UIImage * image){

// resize image
CGSize destinationSize = CGSizeMake(158,187);
UIGraphicsBeginImageContext(destinationSize);
[image drawInRect:CGRectMake(0,0,destinationSize.width,destinationSize.height)];

//新图片
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

//优化图像
NSData * imageDataCompressed = UIImageJPEGRepresentation(newImage,0.4f);

cell.imageView.image = [UIImage imageWithData:imageDataCompressed];
NSLog(@Image Size%@,NSStringFromCGSize(newImage.size)); // log size of image
[cell.activityIndi​​cator stopAnimating];

}失败:^(NSURLRequest *请求,NSHTTPURLResponse *响应,NSError *错误){
NSLog(@无法下载映像:%@,错误)
}];




return cell;

}

最新更新:



设置一个从parse.com获取数据并存储在NSMutableDictionary中然后在可变数组中的方法。我存储的服装的标题,价格和图像的URL。

   - (void)grabDataFromCloud 
{

self.model = [NSMutableArray array];
for(PFObject * object in [self objects]){
PFFile * imageFile = [object valueForKey:@image];
NSURL * url = [NSURL URLWithString:imageFile.url];

NSMutableDictionary * newObject = [NSMutableDictionary dictionaryWithDictionary:@ {@title:[object valueForKey:@title],@price:[object valueForKey:@price],@ imageUrl:url}];
[[self model] addObject:newObject];
}
}

这在我的cellForItemsAtIndexPath方法中被调用。

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

[self grabDataFromCloud];
static NSString * CellIdentifier = @Cell;

VAGGarmentCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];

[cell.activityIndi​​cator setHidden:YES];

NSMutableDictionary * d = [self.model objectAtIndex:indexPath.item];
cell.title.text = d [@title];
cell.price.text = [NSString stringWithFormat:@£%@,d [@price]];

if(d [@image]){
cell.imageView.image = d [@image];
} else {//如果没有,下载它
cell.imageView.image = nil;

dispatch_queue_t backgroundQueue = dispatch_queue_create(test,0);

dispatch_async(backgroundQueue,^ {

NSData * data = [NSData dataWithContentsOfURL:d [@imageUrl]]];
UIImage * img = [UIImage imageWithData :data];
d [@image] = img;
dispatch_async(dispatch_get_main_queue(),^ {
//导致崩溃失败 - [UICollectionView _endItemAnimations],
// /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:3687
// [self.collectionView reloadItemsAtIndexPaths:@ [indexPath]];
});
});

}

return cell;
}


解决方案

我的图像太大了。我不得不调整他们的大小,这立即解决了我的问题。



我从字面上缩小了东西,检查我的图像,发现他们没有被调整大小的方法,我认为是调整大小他们。这是为什么我需要让自己习惯测试。



在过去几天我学到了很多关于GCD和缓存的知识,但是这个问题早就解决了。


Figured out slow loading images were the behind the choppy slow effect of my collectionView. I've been reading different Q&A's all day and various forum posts. It looks like the best way to solve this issue is to have the data pre-loaded available for the cellForItemAtIndexPath to be able to take what it needs.

I'm not sure how I can do this. I'm using parse as my backend, but sure if given a rough example I'd be able to figure out how to do it. From what I've seen so far I need a separate method to grab the data.

Here is the code:

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


-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return [[self objects] count];
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
    NSArray *people = [self objects];
    static NSString *CellIdentifier = @"Cell";

    VAGGarmentCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: CellIdentifier forIndexPath:indexPath];


    PFObject *current;

    current = [people objectAtIndex:indexPath.item];

    PFFile *userImageFile = current[@"image"];

    [userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {
        UIImage *image = [UIImage imageWithData:imageData];

        [[cell contentView] setContentMode: UIViewContentModeScaleAspectFit];
        [[cell imageView] setImage:image];

    }];

    [[cell title] setText:[current valueForKey:@"title"]];
    [[cell price] setText:[NSString stringWithFormat: @"£%@", [current valueForKey:@"price"]]];

    return cell;

}

So maybe the cellForItemAtIndexPath needs to call that method and take what it needs. Because the data would already be available it won't need to be loaded in the cellForItemAtIndexPath method and the cells will be populated immediately.

Please give suggestions and examples.

I was told a good way to do this would be to check for the image, if non existent provide a placeholder, if it does exist set it. Here are the changes to the above code.

Updates:

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

    NSArray *people = [self objects];

    static NSString *CellIdentifier = @"Cell";

    VAGGarmentCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: CellIdentifier forIndexPath:indexPath];



    PFObject *current;

    current = [people objectAtIndex:indexPath.item];



    PFFile *userImageFile = current[@"image"];

    [userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {

        if (!error)
        {

            if (!image) {
                [[cell imageView] setImage:[UIImage imageNamed:@"placeholder.png"]];


            }   else {

                image = [UIImage imageWithData:imageData];


                //resize image
                CGSize destinationSize = CGSizeMake(158,187);
                UIGraphicsBeginImageContext(destinationSize);
                [image drawInRect:CGRectMake(0,0,destinationSize.width, destinationSize.height)];

                //New image
                UIImage*newImage = UIGraphicsGetImageFromCurrentImageContext();
                UIGraphicsEndImageContext();

                //Optimise image
                NSData *imageDataCompressed = UIImageJPEGRepresentation(newImage, 0.4f);
                //  NSLog(@"Image Size %@", NSStringFromCGSize(newImage.size));//log size of image
                    NSLog(@"%@", [current valueForKey:@"title"]);


                [[cell imageView] setImage:[UIImage imageWithData:imageDataCompressed]];



            }

        }

    }];


    [[cell title] setText:[current valueForKey:@"title"]];
    [[cell price] setText:[NSString stringWithFormat: @"£%@", [current valueForKey:@"price"]]];


    return cell;

}

Place holder shows fine but remains, how do I know when the image has been loaded so I can make my cells reflect that?

Thanks for your time. Kind regards.

Update:

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

    NSArray *people = [self objects];

    static NSString *CellIdentifier = @"Cell";

    VAGGarmentCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: CellIdentifier forIndexPath:indexPath];

    [cell.activityIndicator startAnimating];

    PFObject *current;

    current = [people objectAtIndex:indexPath.item];



    PFFile *userImageFile = current[@"image"];

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:userImageFile.url, indexPath.item]];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url                                                                   cachePolicy:NSURLRequestReturnCacheDataDontLoad
                    timeoutInterval:6.0];
                    [cell.imageView setImageWithURLRequest:urlRequest
                    placeholderImage:[UIImage imageNamed:@"placeholder.png"]
                    success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {

                    //resize image
                    CGSize destinationSize = CGSizeMake(158,187);
                    UIGraphicsBeginImageContext(destinationSize);
                    [image drawInRect:CGRectMake(0,0,destinationSize.width, destinationSize.height)];

                    //New image
                    UIImage*newImage = UIGraphicsGetImageFromCurrentImageContext();
                    UIGraphicsEndImageContext();

                    //Optimise image
                    NSData *imageDataCompressed = UIImageJPEGRepresentation(newImage, 0.4f);

                    cell.imageView.image = [UIImage imageWithData:imageDataCompressed];
                    NSLog(@"Image Size %@", NSStringFromCGSize(newImage.size));//log size of image
                   [cell.activityIndicator stopAnimating];

                    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError          *error) {
                    NSLog(@"Failed to download image: %@", error);
                                        }];




    return cell;

}

Latest Update:

Set up a method that gets data from parse.com and stores in an NSMutableDictionary then in a mutable array. I store the title, price and URL to image of the garment.

- (void)grabDataFromCloud
{

    self.model = [NSMutableArray array];
    for (PFObject *object in [self objects]) {
        PFFile *imageFile = [object valueForKey:@"image"];
        NSURL *url = [NSURL URLWithString:imageFile.url];

        NSMutableDictionary *newObject = [NSMutableDictionary dictionaryWithDictionary:@{@"title": [object valueForKey:@"title"], @"price": [object valueForKey:@"price"], @"imageUrl": url}];
        [[self model] addObject:newObject];
    }
} 

This gets called in my cellForItemsAtIndexPath method.

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

    [self grabDataFromCloud];
    static NSString *CellIdentifier = @"Cell";

    VAGGarmentCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: CellIdentifier forIndexPath:indexPath];

    [cell.activityIndicator setHidden:YES];

    NSMutableDictionary* d = [self.model objectAtIndex:indexPath.item];
    cell.title.text = d[@"title"];
    cell.price.text = [NSString stringWithFormat:@"£%@", d[@"price"]];

    if (d[@"image"]) {
         cell.imageView.image = d[@"image"];
    } else { // if not, download it
        cell.imageView.image = nil;

        dispatch_queue_t backgroundQueue = dispatch_queue_create("test", 0);

        dispatch_async(backgroundQueue, ^{

             NSData* data = [NSData dataWithContentsOfURL:d[@"imageUrl"]];
             UIImage* img = [UIImage imageWithData:data];
             d[@"image"] = img;
                 dispatch_async(dispatch_get_main_queue(), ^{
                    //causes crash Assertion failure in -[UICollectionView _endItemAnimations],
                    // /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:3687
                     //   [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
                 });
        });

    }

        return cell;
    }

解决方案

After several days the issue was my images were far too large. I had to resize them and this instantly solved my issue.

I literally narrowed things down and checked my images to find they were not being resized by the method I thought was resizing them. This is why I need to get myself used to testing.

I learnt a lot about GCD and caching in the past few days but this issue could have been solved much earlier.

这篇关于在UICollectionView如何预加载数据以外的cellForItemAtIndexPath在其中使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆