2015-08-20 1 views
1

Я использую представление коллекции с пользовательским макетом. Вызов webservice. Я получил первый раз от API, возвращает 20 объектов, а во второй раз возвращает 1 объект, а при повторной загрузке приложений данных бросает следующая ошибка.UICollectionView выбрасывает неперехваченное исключение с использованием настраиваемого макета

Согласующего приложение из-за неперехваченное исключение 'NSInternalInconsistencyException', причина: UICollectionView получил макет атрибутов для ячейки с индексом путем, который не существует: {длина = 2, путь = 0 - 0}

кусок кода создания нового макета

-(void)doNewLayout 
{ 
id<UICollectionViewDelegateJSPintLayout> delegate = (id<UICollectionViewDelegateJSPintLayout>)self.collectionView.delegate; 

// get column width from delegate. If the method isn't implemented fall back to our property 
    NSUInteger columnWidth = self.columnWidth; 
    if(delegate && [delegate respondsToSelector:@selector(columnWidthForCollectionView:layout:)]) 
    { 
     columnWidth = [delegate columnWidthForCollectionView:self.collectionView 
                 layout:self]; 
    } 

    // find out how many cells there are 
    NSUInteger cellCount = [self.collectionView numberOfItemsInSection:0]; 

    // get max number of columns from the delegate. If the method isn't implemented, fall back to our property 
    NSUInteger maximumNumberOfColumns = self.numberOfColumns; 
    if(delegate && [delegate respondsToSelector:@selector(maximumNumberOfColumnsForCollectionView:layout:)]){ 
     maximumNumberOfColumns = [delegate maximumNumberOfColumnsForCollectionView:self.collectionView layout:self]; 
    } 

    // build an array of all the cell heights. 
    NSMutableArray* cellHeights = [NSMutableArray arrayWithCapacity:cellCount]; 
    for(NSUInteger cellIndex = 0; cellIndex < cellCount; ++cellIndex) 
    { 
     CGFloat itemHeight = self.itemHeight; // set default item size, then optionally override it 
     if(delegate && [delegate respondsToSelector:@selector(collectionView:layout:heightForItemAtIndexPath:)]) 
     { 
      itemHeight = [delegate collectionView:self.collectionView 
              layout:self 
         heightForItemAtIndexPath:[NSIndexPath indexPathForItem:cellIndex 
                     inSection:0]]; 
     } 

     cellHeights[cellIndex] = @(itemHeight); 
    } 

    // now build the array of layout attributes 
    self.pendingLayoutAttributes = [NSMutableArray arrayWithCapacity:cellCount]; 

    // will need an array of column heights 
    CGFloat* columnHeights = calloc(maximumNumberOfColumns,sizeof(CGFloat)); // calloc() initializes to zero. 
    CGFloat contentHeight = 0.0; 
    CGFloat contentWidth = 0.0; 
    for(NSUInteger cellIndex = 0; cellIndex < cellCount; ++cellIndex) 
    { 
     CGFloat itemHeight = [cellHeights[cellIndex] floatValue]; 

     // find shortest column 
     NSUInteger useColumn = 0; 
     CGFloat shortestHeight = DBL_MAX; 
     for(NSUInteger col = 0; col < maximumNumberOfColumns; ++col) 
     { 
      if(columnHeights[col] < shortestHeight) 
      { 
       useColumn = col; 
       shortestHeight = columnHeights[col]; 
      } 
     } 

     NSIndexPath* indexPath = [NSIndexPath indexPathForItem:cellIndex 
                inSection:0]; 
     UICollectionViewLayoutAttributes* layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 

     layoutAttributes.size = CGSizeMake(columnWidth,itemHeight); 
     layoutAttributes.center = CGPointMake((useColumn * (columnWidth + self.interitemSpacing)) + (columnWidth/2.0),columnHeights[useColumn] + (itemHeight/2.0)); 
     self.pendingLayoutAttributes[cellIndex] = layoutAttributes; 
     columnHeights[useColumn] += itemHeight; 
     if(columnHeights[useColumn] > contentHeight) 
      contentHeight = columnHeights[useColumn]; 
     CGFloat rightEdge = (useColumn * (columnWidth + self.interitemSpacing)) + columnWidth; 
     if(rightEdge > contentWidth) 
      contentWidth = rightEdge; 
     columnHeights[useColumn] += self.lineSpacing; 
    } 
    self.contentSize = CGSizeMake(contentWidth,contentHeight+100); 

    free(columnHeights); 
} 

Любое Быстрое решение было бы действительно было оценено

+0

Возможно, вам нужно будет показать еще какой-нибудь код, как вы сообщаете коллекции, сколько ячеек нужно рисовать? – Wez

+0

Добавьте свой собственный код макета, кажется, что вы не создаете layoutAttributes для некоторых всех inexPath, это происходит, когда вы вставляете элементы в представление коллекции, но не изменяете настраиваемые макеты. –

+0

@C_X Добавлен фрагмент кода нового создания макета. – Sathish

ответ

1

Есть несколько вещей, которые необходимо учитывать, поскольку вы являетесь пользовательским макетом, тогда вам нужно создать layoutAttribute для каждого индекса. В вашем случае ваш массив источников данных и offerModel.arrayOffers и self.pendingLayoutAttributes должны быть одинаковыми, если нет, то это может быть проблема и проблема с ее срывом, если у offerModel.arrayOffers есть больше предметов, чем self.pendingLayoutAttributes.

При загрузке асинхр данных, то убедитесь, что при добавлении строки в arraysOffers добавить layoutAttributes в customLayout pendLayoutAttributes, который я думаю, что вы не делаете в данный момент, сделать это путем добавления метода и обеспечить новый indexPaths к тому, что которые создают layoutAttributes.

я обычно делаю, как этот

- (void)insertItems:(NSArray*)items 
{ 
    NSInteger startIndex = <start index for new item>; 
    [self.items addObjectsFromArray:items]; 
    [self calculateLayoutForItems:items startIndex:startIndex]; 
} 

Этот метод расчета layoutAttributes

- (void)calculateLayoutForItems:(NSArray*)items startIndex:(NSInteger)startIndex 
{ 
    // collection view and loop over them as well and nest indexPath creation 

    NSInteger section = 0; 
    NSInteger endIndex = self.items.count; 

    // Lets create indexPaths for provided items and get there frames 
    for (NSInteger index = startIndex ;index < endIndex; index++) 
    { 
     NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:section]; 
     CGRect frame = [self frameForItemAtIndexPath:indexPath];// call your method for frame at indexPath 

     UICollectionViewLayoutAttributes *itemAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 
     itemAttributes.frame = frame; 
     self.pendingLayoutAttributes[indexPath] = itemAttributes; // you can use your index 
    } 
} 

Теперь, когда вы получили больше деталей в источнике данных вызова этого метода на customLayoutObject [self.customLayout insertItems:newItemsArray];

Кроме того, если вам сохранили свойства, а затем переопределили метод invalidate в пользовательском макете, чтобы вернуть все свойства в исходное состояние. Затем вы можете просто invalidatecustomLayout до reloadData метод, после чего просмотр коллекции заставит его снова вычислить макет.

+0

Спасибо за разъяснение. Я добавил ниже инструкции для перезагрузки данных и, похоже, не работает для меня и вызывает те же проблемы, что и я. ** [self.offerCollectionView.collectionViewLayout invalidateLayout]; [offerCollectionView reloadSections: [NSIndexSet indexSetWithIndex: 0]]; [offerCollectionView reloadData]; ** – Sathish

+0

Я обновил свой ответ с помощью примера кода, как вы можете добавить больше элементов в customLyaout –

+0

Вы также можете использовать '-performBatchUpdates:', что приведет к недействительности макета и перезагрузке данных автоматически. Вы должны вставлять/удалять свои объекты внутри этого блока. – pxpgraphics

Смежные вопросы