[英]EXC_BAD_ACCESS on [UICollectionView setCollectionViewLayout:]
[英]Bad Access on [UICollectionView setCollectionViewLayout:animated:]
我在UICollectionView中遇到了一個奇怪的崩潰。 崩潰的UICollectionView嵌入在另一個UICollectionView的UICollectionView單元格中。
我無法重現這個問題,有時如果內部UICollectionView得到新的初始化,因為外部CollectionView正在重新加載它的單元格。
com.apple.main-thread Crashed 0 libobjc.A.dylib objc_msgSend + 9 1 UIKit -[UICollectionViewData _setLayoutAttributes:atGlobalItemIndex:] + 60 2 UIKit __45-[UICollectionViewData validateLayoutInRect:]_block_invoke_0 + 668 3 UIKit -[UICollectionViewData validateLayoutInRect:] + 1408 4 UIKit -[UICollectionViewData layoutAttributesForElementsInRect:] + 82 5 UIKit -[UICollectionView setCollectionViewLayout:animated:] + 1644 6 MyApp BSCTopnewsCollectionView.m line 52 -[BSCTopnewsCollectionView setupBSCTopnewsCollectionView] 7 MyApp BSCTopnewsCollectionView.m line 27 -[BSCTopnewsCollectionView setWeakDelegatePointer:] 8 Myapp BSCFrontPageViewController.m line 550 -[BSCFrontPageViewController collectionView:cellForItemAtIndexPath:] 9 UIKit -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:] + 252 10 UIKit -[UICollectionView _updateVisibleCellsNow:] + 2672 11 UIKit -[UICollectionView layoutSubviews] + 214 12 UIKit -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 258 13 QuartzCore -[CALayer layoutSublayers] + 214 14 QuartzCore CA::Layer::layout_if_needed(CA::Transaction*) + 460 15 QuartzCore CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16 16 QuartzCore CA::Context::commit_transaction(CA::Transaction*) + 238 17 QuartzCore CA::Transaction::commit() + 316 18 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 60 19 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20 25 UIKit UIApplicationMain + 1120 26 MyApp main.m line 16 main Exception Type: EXC_BAD_ACCESS Code: KERN_INVALID_ADDRESS at 0x158848
我在setupBSCTopnewsCollectionView的第52行中所做的是
BSCInfiniteLayout *infiniteLayout = [[BSCInfiniteLayout alloc] init]; (line 52) self.collectionView.collectionViewLayout = infiniteLayout;
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { if([collectionView isEqual:self.collectionView]) { if(indexPath.row == 0) // Header Cell { BSCTopnewsCollectionView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:BSCHeaderReuseIdentifier forIndexPath:indexPath]; cell.dataSource = self; cell.weakDelegatePointer = self; self.topNewsCollectionView = cell; return cell; } else { //create normal cells } } else if ([collectionView isEqual:self.topNewsCollectionView.collectionView]) { BSCTopNewsHeaderCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:BSCTopNewsCellReuseIdentifier forIndexPath:indexPath]; BSCNews *topnews = [self.topNews objectAtIndex:indexPath.row]; [cell setEntity:topnews]; return cell; } }
該方法的一些說明要求:
- (void)setWeakDelegatePointer:(BSCFrontPageViewController *)weakDelegatePointer { _weakDelegatePointer = weakDelegatePointer; [self setupBSCTopnewsCollectionView]; [self.collectionView reloadData]; } - (void)setupBSCTopnewsCollectionView { self.collectionView.delegate = self.weakDelegatePointer; self.collectionView.dataSource = self.weakDelegatePointer; BSCInfiniteLayout *infiniteLayout = [[BSCInfiniteLayout alloc] init]; infiniteLayout.delegate = self; // Setup Layout self.collectionView.collectionViewLayout = infiniteLayout; self.collectionView.showsHorizontalScrollIndicator = NO; self.collectionView.pagingEnabled = YES; // Register Cells [self.collectionView registerNib:[UINib nibWithNibName:@"BSCTopNewsHeaderCell" bundle:nil] forCellWithReuseIdentifier:BSCTopNewsCellReuseIdentifier]; }
如果在應用程序運行時重新加載CollectionView而不是在開頭的后台,一切都很好。
首先,將UICollectionView拖放到XIB中的ViewController,將Delegate,datasource掛鈎到ViewController(這只是主ViewController)
不要為1個CollectionView使用2個不同的筆尖單元格,因為您只能注冊1個筆尖。 最好使用DecorationView作為HeaderView。 創建新類HeaderView:UICollectionReusableView。 這個UICollectionReusableView是UIView的子類,可以與UICollectionViewCell一起在UICollectionView中重用。 現在您可以注冊兩種類型:
[self.collectionView registerNib:[UINib nibWithNibName:@"MyCell" bundle:nil] forCellWithReuseIdentifier:@"CELL"];
[self.collectionView registerNib:[UINib nibWithNibName:@"HeaderView" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderCell"];
接下來,將另一個UICollectionView拖到此HeaderView,與HeaderView.h中的IBOutlet連接。 在這里,最好將Delegate,DataSource設置為此類以進行控制。 同時注冊此CollectionView將使用的Nib Cell。 在awakeFromNib中執行它是因為之前注冊了NFS
- (void)awakeFromNib{
[self.topCollectionView registerNib:[UINib nibWithNibName:@"TopCell" bundle:nil] forCellWithReuseIdentifier:@"TopCell"];
[self.topCollectionView setDataSource:self];
[self.topCollectionView setDelegate:self];
}
它會很好用,如果你將數據源存儲在外面,只需創建另一個屬性並分配給它,然后在這里用於返回數據源內部。
如果您想知道何時單擊headerView中的Cell,請在單擊HeaderCell時使用customDelegate協議將委托發送到ViewController。
這是我的代碼,希望您理解並在此處應用您的數據:
https://github.com/lequysang/gitfiles02/blob/master/CollectionViewWithDecorationView.zip
看起來你的委托或內部集合視圖已經死了(setWeakDelegatePointer:做什么?)。 在模擬器上嘗試Zombies儀器,它應該標記僵屍是否是這種情況。 還為xCode中的所有異常設置“異常斷點”(當從xCode運行應用程序而不是儀器時,將幫助您進行調試)。 還要檢查你的-[BSCFrontPageViewController collectionView:cellForItemAtIndexPath:]
實現,它可能會在重用時釋放內部集合視圖。
編輯:為什么不將標題單元格添加為標題而不是單元格0( 此處集合視圖中的標題示例)? 當您為外部集合視圖創建正常單元格時,還要檢查(只是為了確保它不是崩潰的原因)重用標識符。 在模擬器上調試時,還要定期發送mem警告。
另外,為什么要使用標題的另一個集合視圖? 您可以使用與iCarousel類似的內容進行此類布局。
您可以嘗試以下操作,滾動主要的uicollectionview,以便標題不顯示...(更好)然后在模擬器上嘗試執行內存警告...使用硬件 - >模擬內存警告...
這可能應該創建一個單元格回收和刪除(uicollectionview應該銷毀任何現在不重要的東西......如果發生這種情況,標題將被取消分配,你仍然持有一個弱引用...所以你做的任何事情會因為訪問不當而發生...這也是因為缺少內存警告(僅限於您以明確方式創建的內容)而在模擬器上重現“不可能”。
視圖看起來很重,所以你可以嘗試這樣做並發布結果嗎?
從評論中提取我們的“答案”。
可悲的是,沒有一個答案有幫助。 我最終重構了整個事情然后問題消失了。 我甚至與蘋果DTS工程師進行了非常詳細的交談,他也不知道該怎么做。 所以我們只是重構了。 對不起:/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.