一次从xib修改为纯代码带来的惨剧

今天在项目中遇到一个问题,是UICollectionView的一个DataSource方法- (UICollectionReusableView *)collectionView: viewForSupplementaryElementOfKind: atIndexPath:在同一个VC中被重复调用,第一次调用是正常的,第二次调用就会返回nil,导致crash,而这个方法是不允许返回crash的。

几经定位,最后找到的原因哭笑不得,竟然是忘记删了VC的xib文件。

起因是项目中这个VC之前用了Xib,为了使它更通用,以及以后使用JSPatch打补丁方便,就想把它改成纯代码实现。其中的核心控件是一个自定义的UICollectionView。

我把IBOutlet关联的collectionview属性删除了IBOutlet,这样是删除了关联,并用纯代码创建了对应的collectionView。但是,最大的大意是没有删除VC对应的xib文件。

因为我之前在创建CustomViewController时,是勾选了Also Create XIB file的,那么在用[[CustomViewController alloc]init]创建VC时,系统会自动在mainBundle中寻找同名的xib文件并加载。

这就意味在在加载xib时创建了一个collectionView对象A,同时在我的纯代码中也创建了另一个collectionView对象B,两者的DataSource和Delegate都指向了VC。而我在注册header class时,是用self.collectionView注册的,也就是说只有纯代码创建的collectionView才注册了header class。因为collectionView对象A没有注册header class,那么在使用- (UICollectionReusableView *)collectionView: viewForSupplementaryElementOfKind: atIndexPath:获取对应的UICollectionReusableView对象时,用dequeueReusableSupplementaryViewOfKind: withReuseIdentifier: forIndexPath:方法得到的返回值永远为nil,这就会导致crash。

解决方法就是删除VC对应的xib文件,就这么简单。

相关的错误日志:

*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-2903.2/UICollectionView.m:1401

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath

(UICollectionElementKindSectionHeader,<NSIndexPath: 0x145f3f50> {length = 2, path = 0 - 0}) was not retrieved by calling -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: or is nil'

(<UICollectionReusableView: 0x145f9400; frame = (0 0; 320 20); layer = <CALayer: 0x145f90c0>>)

*** Assertion failure in -[DFCollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.30.14/UICollectionView.m:3690

Exception: could not dequeue a view of kind: UICollectionElementKindSectionHeader with identifier CollectionEmptyDataHeader - must register a nib or a class for the identifier or connect a prototype cell in a storyboard

*** Assertion failure in -[DFCollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.30.14/UICollectionView.m:1583

libc++abi.dylib: terminate_handler unexpectedly threw an exception


if(kind == UICollectionElementKindSectionHeader)
{
    @try {
        theView = [theCollectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header" forIndexPath:theIndexPath];
    }
    @catch (NSException * e) {
        NSLog(@"Exception: %@", e);
        theView = [[UICollectionReusableView alloc] init];
    }
    @finally {
        return theView;
    }

}

这份代码虽然没起作用,不建议使用,但是调试时可以用其中的NSLog打印的信息来辅助定位问题。来源:uicollectionview - viewForSupplementaryElementOfKind is crashing on "index 0 beyond bounds for empty array" - Stack Overflow 

这里有一个类似的问题,但问题原因完全不一样:

iOS UICollectionView 的坑:不能重复调用 dequeueReusableSupplementaryViewOfKind - 简书 


转载于:https://my.oschina.net/ioslighter/blog/666635

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值