Reputation: 185
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
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