raginggoat
raginggoat

Reputation: 3600

UICollectionView Crashes on iOS 7

I have an app that shows the newest 50 images from a Flickr photo stream in a collection view. It works fine on iOS 6 but crashes on iOS 7. If I uninstall the app and reinstall it, it works fine the first time I load that view. When i back out of that view and then go back to it, it crashes. Any ideas?

This is the error I get:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'too many update animations on one view - limit is 15 in flight at a time (; }; layer = >)'

.h

#import <UIKit/UIKit.h>
#import <dispatch/dispatch.h>
#import "KFBFlickrPhotoManager.h"
#import "KFBImageDetailViewController.h"

@interface KFBFlickrViewController : UIViewController <NSURLConnectionDelegate,NSURLConnectionDataDelegate, UICollectionViewDataSource,UICollectionViewDelegate,FlickrPhotoDelegate, UIGestureRecognizerDelegate>
{

    NSMutableArray *imageInfo;
}

@property (retain) NSMutableArray * imageInfo;
@property (retain) KFBFlickrPhotoManager * imageManager;
@property (retain) NSString * html;

@property (nonatomic, retain) NSString *apiKey;
@property (retain, nonatomic) IBOutlet UICollectionView *photoCollectionView;
@property (retain) KFBImageDetailViewController *imageDetailViewController;
@end

.m

#import "KFBFlickrViewController.h"
#import "KFBFlickrPhoto.h"

@interface KFBFlickrViewController ()

@end

@implementation KFBFlickrViewController

@synthesize apiKey=apiKey;
@synthesize photoCollectionView, imageManager, imageInfo,imageDetailViewController;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        apiKey = @"a70fe2e828e66660c74ce0a7c34a55aa";
        NSString *urlString = [NSString stringWithFormat:@"http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=%@&per_page=50&user_id=52540720@N02&format=json&nojsoncallback=1", apiKey];

        NSURL *url = [NSURL URLWithString:urlString];

        imageInfo = [NSMutableArray array];

        self.imageInfo = [[NSMutableArray alloc] init];
        self.imageManager = [[KFBFlickrPhotoManager alloc] initWithURL:url delegate:self];
        [imageManager process];


        imageInfo = [NSMutableArray array];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(imageUpdated:) name:@"com.KFB.imageupdated" object:nil];
        // Custom initialization
    }
    return self;
}

-(void)viewDidAppear:(BOOL)animated
{
    //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(imageUpdated:) name:@"com.KFB.imageupdated" object:nil];
}

-(void)viewDidDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"com.razeware.imagegrabber.imageupdated" object:nil];
}

-(void)showFlickr
{
    NSURL *url = [NSURL URLWithString:@"http://www.kyfb.com/photos"];
    [[UIApplication sharedApplication] openURL:url];
}

-(void)viewDidLoad
{
    [super viewDidLoad];

    self.navigationItem.title = @"Photos";
    UINib *cellNib = [UINib nibWithNibName:@"CVCell" bundle:nil];
    [self.photoCollectionView registerNib:cellNib forCellWithReuseIdentifier:@"photoCell"];

    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
    [flowLayout setItemSize:CGSizeMake(75, 75)];
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
    [flowLayout setSectionInset:UIEdgeInsetsMake(10, 10, 10, 10)];
    [self.photoCollectionView setCollectionViewLayout:flowLayout];

    UIBarButtonItem *openFlickr = [[UIBarButtonItem alloc] initWithTitle:@"More Photos" style:UIBarButtonItemStyleBordered target:self action:@selector(showFlickr)];
    self.navigationItem.rightBarButtonItem = openFlickr;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

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

    static NSString *cellIdentifier = @"photoCell";

    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

    KFBFlickrPhoto * info = [imageInfo objectAtIndex:indexPath.row];
    UIImageView *imageView = (UIImageView*)[cell viewWithTag:2020];
    imageView.image = info.image;

    return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    KFBFlickrPhoto *photo = [imageInfo objectAtIndex:indexPath.row];
        self.imageDetailViewController = [[KFBImageDetailViewController alloc] initWithNibName:@"KFBImageDetailViewController" bundle:[NSBundle mainBundle]];
    imageDetailViewController.photo = photo;
    [self.navigationController pushViewController:imageDetailViewController animated:YES];
}


-(void)imagesAvailable:(NSArray *)images done:(BOOL)done {

    NSLog(@"Image infos available: %d!", images.count);

    NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:images.count];
    for(int i = imageInfo.count; i < imageInfo.count + images.count; ++i) {
        NSIndexPath * indexPath = [NSIndexPath indexPathForRow:i inSection:0];
        [indexPaths addObject:indexPath];
    }
    [imageInfo addObjectsFromArray:images];
    [photoCollectionView insertItemsAtIndexPaths:indexPaths];
    //[photoCollectionView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];

}


- (void)imageUpdated:(NSNotification *)notif {

    UIImage *info = [notif object];
    int row = [imageInfo indexOfObject:info];
    NSIndexPath * indexPath = [NSIndexPath indexPathForRow:row inSection:0];

    NSLog(@"Image for row %d updated!", row);
    [photoCollectionView reloadItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
    //[photoCollectionView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

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

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

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Upvotes: 4

Views: 2654

Answers (1)

Dean
Dean

Reputation: 939

After doing a little research I think a better approach would be to try the performBatchUpdates:completion: method of UICollectionView. Your method would end-up looking something like this:

-(void)imagesAvailable:(NSArray *)images done:(BOOL)done {

[photoCollectionView performBatchUpdates:^{
    NSLog(@"Image infos available: %d!", images.count);

    NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:images.count];
    for(int i = imageInfo.count; i < imageInfo.count + images.count; ++i) {
        NSIndexPath * indexPath = [NSIndexPath indexPathForRow:i inSection:0];
        [indexPaths addObject:indexPath];
    }
    [imageInfo addObjectsFromArray:images];
    [photoCollectionView insertItemsAtIndexPaths:indexPaths];
} completion:nil];

}

See SO question on UICollectionView updates for more details.

Upvotes: 1

Related Questions