UICollectionView冻结iOS应用程序

时间:2014-12-13 11:58:06

标签: ios objective-c iphone uicollectionview

早上好,

我第一次使用 UICollectionView 来显示来自用户的图片(比如Facebook个人资料),此刻我可以很好地展示图片,但我遇到了一些问题:

1-当我访问我的个人资料时,由于加载了5张图片,该应用会冻结2-3分钟。

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

提前致谢。

5 个答案:

答案 0 :(得分: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 :(得分: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

答案 2 :(得分:0)

尝试为集合视图注册Nib

在viewController的viewDidLoad()方法中编写以下代码:

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

我认为你必须在集合视图中使用https://github.com/nicklockwood/AsyncImageView来加载图像。

对于Storyboard,您必须看到本教程:http://www.appcoda.com/ios-programming-uicollectionview-tutorial/这将为您提供更多帮助。

谢谢!

答案 3 :(得分:0)

对于第一个问题,答案就在这行代码中:

NSData * data = [NSData dataWithContentsOfURL:url];

来自Apple Reference

  

请勿使用此同步方法来请求基于网络的网址。对于   基于网络的URL,此方法可以阻止当前线程为数十   慢速网络上的秒数,导致用户体验不佳,以及   在iOS中,可能会导致您的应用被终止。

作为替代方案,您可以使用NSURLSessionDataTask下载数据(请参阅Apple Reference

<强> - 编辑

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

}

我希望这可以帮到你。

- 编辑2 对于未来的读者,我根据@ suhit的回答(对他来说+1)稍微重构了我的代码

答案 4 :(得分:0)

您可以使用调度程序为下载图像创建异步操作。这将解决您遇到的两个问题:

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