iOS 10 버그 : UICollectionView가 존재하지 않는 인덱스 경로가있는 셀에 대한 레이아웃 속성을 받았습니다.
iOS 10이 설치된 기기에서 내 앱을 실행하면이 오류가 발생합니다.
UICollectionView가 존재하지 않는 인덱스 경로가있는 셀에 대한 레이아웃 속성을 받았습니다.
iOS 8 및 9에서는 잘 작동합니다. 나는 조사 중이며 컬렉션 뷰 레이아웃을 무효화하는 것과 관련된 것을 발견했습니다. 성공하지 못한 채 그 솔루션을 구현하려고했기 때문에 직접적인 도움을 요청하고 싶습니다. 이것은 내 계층 뷰입니다.
->Table view
->Each cell of table is a custom collection view [GitHub Repo][1]
->Each item of collection view has another collection view
내가 시도한 것은 삽입하는 것입니다
[self.collectionView.collectionViewLayout invalidateLayout];
에서
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
두 컬렉션보기의
또한 데이터를 다시로드하기 전에 레이아웃을 무효화하려고했지만 작동하지 않습니다.
누구든지 나에게 길을 안내해 줄 수 있습니까?
collectionView의 셀 수가 변경되었을 때 이런 일이 발생했습니다. reloadData를 호출 한 후 invalidateLayout이 누락 된 것으로 나타났습니다. 추가 한 후 더 이상 충돌이 발생하지 않았습니다. Apple은 iOS10의 collectionViews를 일부 수정했습니다. 이것이 이전 버전에서 동일한 문제가 발생하지 않는 이유라고 생각합니다.
내 최종 코드는 다음과 같습니다.
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
사용자 정의 레이아웃이있는 경우 prepare func를 재정의하는 동안 캐시 (UICollectionViewLayoutAttributes)를 지워야합니다.
override func prepare() {
super.prepare()
cache.removeAll()
}
두 컬렉션에 동일한 UICollectionViewFlowLayout을 추가했기 때문에 동일한 뷰에서 2 개의 collectionView로이 문제에 직면했습니다.
let layout = UICollectionViewFlowLayout()
collectionView1.collectionViewLayout = layout
collectionView2.collectionViewLayout = layout
물론 collectionView1 데이터가 변경되면 데이터를 다시로드 할 때 충돌이 발생합니다. 이것이 누군가를 도울 수 있다면.
이전 답변이 도움이되지만 자동 크기 조정 셀을 사용하면 크기가 올바르지 않습니다.
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.estimatedItemSize = CGSizeMake(60, 25);
layout.itemSize = UICollectionViewFlowLayoutAutomaticSize;
self.collectionView.collectionViewLayout = layout;
나는 교체 하여이 문제를 해결합니다.
[self.collectionView reloadData];
...에
[self.collectionView reloadSections:indexSet];
@Katrin의 답변은 많은 도움이되었지만 한 줄을 더 추가하면 더 나은 결과를 얻을 수 있습니다.
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
collectionView.layoutSubviews() // <-- here it is :)
이 라인으로 크래시를 재현 할 수 있는지 아닌지는 지금 말할 수 없지만, 하나가있는 것 같네요 ... 그래도 은색 총알이 아니라 뭔가.
UICollectionView
의 레이아웃을 재설정 하면 문제가 해결되었습니다.
let layout = UICollectionViewFlowLayout()
collectionView?.collectionViewLayout = layout
invalidateLayout
제 경우에는 전화 가 충돌을 막지 못했습니다. (컬렉션 뷰의 항목 수가 증가하면 작동하지만 감소하면 작동하지 않습니다). 컨텍스트 : UITableViewCell 내부에 UICollectionView가 있고 테이블 셀을 다시 사용할 때 collectionView의 대리자를 재설정합니다. 캐시를 무효화하는 것이 아니라 델리게이트를 재설정 할 때마다 레이아웃 객체를 다시 생성 한 다음 reloadData ()를 호출하여 문제를 해결했습니다.
foo.dataSource = newDataSource
foo.delegate = newDelegate
foo.fixLayoutBug()
foo.reloadData()
func fixLayoutBug() {
let oldLayout = collectionViewLayout as! UICollectionViewFlowLayout
let newLayout = UICollectionViewFlowLayout()
newLayout.estimatedItemSize = oldLayout.estimatedItemSize
newLayout.footerReferenceSize = oldLayout.footerReferenceSize
newLayout.headerReferenceSize = oldLayout.headerReferenceSize
newLayout.itemSize = oldLayout.itemSize
newLayout.minimumInteritemSpacing = oldLayout.minimumInteritemSpacing
newLayout.minimumLineSpacing = oldLayout.minimumLineSpacing
newLayout.scrollDirection = oldLayout.scrollDirection
newLayout.sectionFootersPinToVisibleBounds = oldLayout.sectionFootersPinToVisibleBounds
newLayout.sectionHeadersPinToVisibleBounds = oldLayout.sectionHeadersPinToVisibleBounds
newLayout.sectionInset = oldLayout.sectionInset
newLayout.sectionInsetReference = oldLayout.sectionInsetReference
collectionViewLayout = newLayout
}
매번 데이터를 다시로드하는 것은 좋지 않습니다 (insertItems 및 deleteItems, 심지어 reloadSections를 사용해야 함). 하지만 ... 어떤 경우에는 유효하다고 말한 후 실제로 다음을 수행 할 수 있습니다.
collectionView.dataSource = nil
collectionView.delegate = nil
/*... All changes here. ... */
collectionView.dataSource = self
collectionView.delegate = self
collectionView.reloadData()
제 경우에는 NSlayoutConstraint 상수를 변경했습니다.
self.collectionViewContacts.collectionViewLayout.invalidateLayout()
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
self.collectionViewContacts.reloadData()
문제를 해결
RxDataSources 를 사용하는 데 문제가 있었고 RxCollectionViewSectionedAnimatedDataSource
두 가지 답변을 결합하여 해결했습니다. invalidateLayout()
내 컬렉션을 반응 적으로 다시로드 해야합니다 .
...
.asDriver(onErrorJustReturn: [])
.do(onNext: { [weak self] _ in
DispatchQueue.main.async {
self?.collectionViewLayout.invalidateLayout()
self?.collectionView.layoutSubviews()
}
}).drive(collectionView.rx.items(dataSource: collectionController.dataSource))
.disposed(by: disposeBag)
레이아웃 방법 cache
에서 배열 을 지우십시오 prepare()
. 다음은 코드입니다.
override func prepare() {
super.prepare()
cache.removeAll()
guard let collectionView = collectionView,
collectionView.numberOfSections > 0,
let delegate = delegate else {
return
}
...
스크롤 위치를 유지하고 충돌을 수정하려면 다음을 사용할 수 있습니다.
collectionView.reloadData()
let context = collectionView.collectionViewLayout.invalidationContext(forBoundsChange: collectionView.bounds)
context.contentOffsetAdjustment = CGPoint.zero
collectionView.collectionViewLayout.invalidateLayout(with: context)
애니메이션 제약 변경을 사용하여 컬렉션보기를 숨기는 동안 비슷한 문제에 직면했습니다. 내 솔루션은 기존 답변을 기반으로합니다.
self.filtersCollectionView.reloadData()
if isNeedToUpdateConstraint {
filtersCollectionViewHeightLayoutConstraint.constant = updatedHeight
UIView.animate(withDuration: 0.1, animations: {
self.view.setNeedsLayout()
}, completion: { completion in
if completion {
self.filtersCollectionView.collectionViewLayout.invalidateLayout()
}
})
}
I had this problem as well. In my case there was a custom UICollectionViewLayout
applied to the collection view & the problem was that it had stale data for the number of cells that should be displayed. That's definitely something you can check on when you see UICollectionView received layout attributes for a cell with an index path that does not exist
I managed to solve this by recreating the collectionViewLayout
before calling reloadData()
The issue was probably related to me having a separate instance for the dataSource
(i.e. not the view controller holding the collectionView), and when swapping datasource, the crash could appear.
This happened to me as well, but it was because my UICollectionViewDataSource
changed, and I didn't call -[UICollectionView reloadData]
. In my case, I had the following data structure:
struct Bar { let name: String }
struct Foo { let name: String; let bars: [Bar] }
I had two UICollectionView
s: one for Foo
s and one for Bar
s. In my -collectionView:didSelectItemAtIndexPath:
, I had the following:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if (collectionView == self.fooCollectionView) {
self.selectedFoo = self.foos[indexPath.row];
[self.barCollectionView reloadData];
self.fooCollectionView.hidden = YES;
self.barCollectionView.hidden = NO;
} else if (collectionView == self.barCollectionView) {
// do some stuff with the selected bar
self.selectedFoo = nil;
// This -reloadData call fixed my error. I thought I didn't
// need it since my UICollectionView was hidden
[self.barCollectionView reloadData];
self.barCollectionView.hidden = YES;
self.fooCollectionView.hidden = NO;
}
}
Without the -reloadData
call, I would see the crash when I rotated the device.
After spending two days of time, the below code solved the issue. Before loading a collectionview write the below code.
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
collecView.collectionViewLayout = flowLayout
collecView.delegate = self
collecView.dataSource = self
collecView.reloadData()
Then the crash will be resolved, but you will find issue in collectionview cells, as the cells are compressed or not as per your design. Then just a line of code after scrolldirection line
flowLayout.itemSize = CGSize(width: 92, height: 100)
With the above line of code, you can adjust you collectionview cell layout.
I hope it will help someone.
In my case I was changing the constant of NSLayoutConstraint none of the above solution worked for me. thanks to @jeff ayan whose answer gave me the hint. I solved the problem with this code
override func prepareForReuse() {
super.prepareForReuse()
imagesCollectionHeight.constant = 100 // changing collectionview height constant
imageContainerWidth.constant = 100 //changing width constant of some view
self.layoutIfNeeded() // this line did the trick for me
}
Hope it helps someone
The following made it for me:
[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];
This code seems to force collectionView to scroll to the first cell before reloading data, what seems to cause the error in my case.
'developer tip' 카테고리의 다른 글
Eclipse / Java-R.string. *의 값은 int를 반환합니까? (0) | 2020.11.23 |
---|---|
foreach 루프에서 배열 값 설정 해제 (0) | 2020.11.23 |
뒤로 버튼을 누른 조각에서 활동이 비어 있습니다. (0) | 2020.11.22 |
FragmentManager가 이미 트랜잭션을 실행하고 있습니다. (0) | 2020.11.22 |
Rails — 텍스트 영역에 줄 바꿈 추가 (0) | 2020.11.22 |