Marco Castorina
Marco Castorina

Reputation: 185

Derived UICollectionViewCell always returns null from dequeueReusableCellWithReuseIdentifier

I'm adding a UICollectionView programmatically to a controller, but no matter how I set it up, I can't get a valid UICollectionViewCell when calling dequeueReusableCellWithReuseIdentifier. Before showing the code, some info that might be helpful:

Here's the code:

Controller.h

@interface ViewController : UIViewController<UIImagePickerControllerDelegate, UICollectionViewDelegate, UICollectionViewDataSource>

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;

@end

Controller.m

@interface ViewController ()

@property (strong, nonatomic) NSMutableArray *images;
@property (strong, nonatomic) UICollectionView *collectionView;

@end

// called by a button in the navigation bar
- (void)addMedia:(id)sender {
    // load test images
    if ([self.images count] == 0) {
        NSBundle *myBundle = [NSBundle mainBundle];
        NSArray *imagesPaths = [myBundle pathsForResourcesOfType:@"png" inDirectory:nil];

        for (NSString *path in imagesPaths) {
            UIImage *newImage = [[UIImage alloc] initWithContentsOfFile:path];

            [self.images addObject:newImage];
        }

        self.introLabel.hidden = YES;

        CGRect rect = CGRectMake(self.view.frame.size.width / 2 - 250,
                                 self.view.frame.size.height / 2 - 250, 500, 500);
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        layout.itemSize = CGSizeMake(120, 120);
        layout.minimumInteritemSpacing = 10;
        self.collectionView = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
        UINib *cellNib = [UINib nibWithNibName:@"ImageViewCell" bundle:nil];
        [self. collectionView registerNib:cellNib forCellWithReuseIdentifier:@"imageCell"];
        //[self.collectionView registerClass:[ImageViewCell class] forCellWithReuseIdentifier:@"imageCell"];
        [self.collectionView setDelegate:self];
        [self.collectionView setDataSource:self];
        [self.view addSubview:self.collectionView];
    }
}

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

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    // THIS IS ALWAYS NULL
    ImageViewCell *cell = (ImageViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"imageCell" forIndexPath:indexPath];

    cell.image.image = [self.images objectAtIndex:indexPath.row];

    return cell;
}

ImageViewCell.h

@interface ImageViewCell : UICollectionViewCell

@property (strong, nonatomic) IBOutlet UIImageView *image;

@end

ImageViewCell.m

@implementation ImageViewCell

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    // THIS IS ALWAYS NULL!
    return self;
}

@end

In the ImageViewCell.xib I have a UICollectionCellView as the main view, which contains the UIImageView I'm trying to populate; the UICollectionCellView points to ImageViewCell (the derived class).

I should mention that I tried the same approach with a new project with a single controller and adding programmatically the UICollectionView and it works, so I must be missing something silly or doing something slightly different but I'm not aware of it.

[EDIT]: changed the code with solution.

Upvotes: 0

Views: 1049

Answers (1)

sammoore
sammoore

Reputation: 330

Make sure in the xib file that the File's Owner property indicates the class name that implements it. Then, implement:

- (NSString *)reuseIdentifier {
    return @"imageCell";
}

in your ImageViewCell implementation. There also might be a way to set this in interface builder, rather than overriding the getter.

By the way, if your ImageViewCell is backed by a xib, initWithFrame: will not be the designated initializer, but instead initWithCoder will be. But your implementation is fine as is, and you don't necessarily need to override initWithCoder at this point.

EDIT: as rdelmar pointed out, you should definitely be using the registerNib version as well; you wouldn't need to implement the reuseIdentifier getter this way.

Upvotes: 1

Related Questions