Question

I am using a UICollectionView to produce a grid of cells say total of 10 i.e. 0-9.

Now, I want to insert a new cell in the grid on click of one of the cells.

so I have added the following line of code [_collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:10 inSection:0]]]; inside the function didSelectItemAtIndexPath.

So now, if I set indexPathForItem: as 10 (i.e. insert at last) then I get 'Assertion failure' error on this line. If I set `indexPathForItem:' anything between 0-9 then I get 'EXC_BAD_ACCESS...' error on this line.

This is my complete code implementing UICollectionView:

- (void)loadView
{
    self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];


    UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
    _collectionView=[[UICollectionView alloc] initWithFrame:CGRectMake(0, 97.5,                                                     self.view.frame.size.width, self.view.frame.size.height-67.5) collectionViewLayout:layout];
    [_collectionView setDataSource:self];
    [_collectionView setDelegate:self];

    [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
    [_collectionView setBackgroundColor:[UIColor whiteColor]];

    [self.view addSubview:_collectionView];

}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:    (NSInteger)section
{
    return 35;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];

    cell.layer.borderWidth=.5f;
    cell.layer.borderColor=[UIColor blackColor].CGColor;

    if(indexPath.item<31)
    {
        _dayNumber = [[UILabel alloc] initWithFrame:CGRectMake(30, 30, 15, 15)];
        _dayNumber.font = [UIFont systemFontOfSize:12];
        _dayNumber.text = [NSString stringWithFormat:@"%ld",(indexPath.item + 1)];
        [cell addSubview:_dayNumber];
    }


    return cell;
}   

- (CGSize)collectionView:(UICollectionView *)collectionView layout:    (UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(self.view.frame.size.width/7, self.view.frame.size.width/7);
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:    (UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:    (NSInteger)section
{
    return 0.0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
    return 0.0;
}

// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:    (UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(0,0,0,0);  // top, left, bottom, right
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:    (NSIndexPath *)indexPath
{
    [_collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:0]]];
}

Any help?

Was it helpful?

Solution

Well,

first let's consider this method,

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:    (NSInteger)section
{
    return 35;  // returning constant value means that you can't add or remove cells later
}

so let me change this to

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:    (NSInteger)section
{
    return self.itemsCount;
}

declare itemsCount property in your class interface, like this

@interface YourClass ()
@property (nonatomic) NSInteger itemsCount;
@end

initialize it in loadView or init method,

_itemsCount = 35;   // or whatever you want, initial count

now we can insert/delete items, right ? when we call insertItemAtIndexPaths all we have to do is updating actual data before that call, (for example self.itemsCount++, [self.myItems addObject:newItem] ) here is changes in your code

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    self.itemsCount++;   // updating data
    [_collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:0]]];
}

One last important thing, in cellForItemAtIndexPath don't alloc init any kind of view and add as subview on cell, this code every time creates UILabels on cell, if you want custom view on cell (like an imageview, button, etc ..) you should subclass UICollectionViewCell and create this stuff in it's init method, here is how it will look like

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    YourCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];

    cell.layer.borderWidth = 0.5;
    cell.layer.borderColor = [UIColor blackColor].CGColor;

    cell.dayNumber.font = [UIFont systemFontOfSize:12];
    cell.dayNumber.text = [NSString stringWithFormat:@"%d",(indexPath.row + 1)];

    return cell;
}

assuming you also changed this line,

[_collectionView registerClass:[YourCell class] forCellWithReuseIdentifier:@"cellIdentifier"];

note that YourCell is a subclass of UICollectionViewCell and has property dayNumber

Apple has a great guide about collection views. I recommend to read it. Good luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top