Objective-C加载自定义Xib关联Outlet触发NSUnknownKeyException报错求助
NSUnknownKeyException 异常修复方案
问题场景与报错信息
开发Objective-C项目时,自定义CollectionViewCell的Xib并关联Outlet后,出现如下崩溃:
2023-06-07 22:50:32.194106-0700 ProturisApp[91070:2437111] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<InputCollectionViewCell 0x10403ee78> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key brickWall.'
相关代码如下:
UIView分类(NIBLoader)
@implementation UIView (NIBLoader) + (instancetype)fromNib { return [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil] objectAtIndex:0]; } @end
InputCollectionViewCell实现
#import "InputCollectionViewCell.h" #define IDENTIFFIER @"InputCollectionViewCell" @implementation InputCollectionViewCell -(instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self loadFromNib]; } return self; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self loadFromNib]; self.userInteractionEnabled = YES; // Initialize what is needed } return self; } + (NSString *) identifier { return IDENTIFFIER; } - (void)loadFromNib { UIView *nibView = [[self class] fromNib]; if (nibView) { nibView.frame = self.bounds; nibView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self addSubview:nibView]; nibView.backgroundColor = [UIColor redColor]; } } @end
MainViewController关键代码
#import "MainViewController.h" @interface MainViewController () @end @implementation MainViewController @synthesize menuCollectionView; - (void)viewDidLoad { [super viewDidLoad]; [self.menuCollectionView registerClass:[InputCollectionViewCell class] forCellWithReuseIdentifier:[InputCollectionViewCell identifier]]; menuCollectionView.delegate = self; menuCollectionView.dataSource = self; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [InputCollectionViewCell dealloc]; } - (nonnull __kindof UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { // Dequeue a reusable cell from the collection view. InputCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[InputCollectionViewCell identifier] forIndexPath:indexPath]; [cell addBorderAndShadow]; // Configure the cell with data for the index path. // MyData *data = self.myDataArray[indexPath.item]; // [cell configureWithData:data]; // Return the configured cell. return cell; } @end
Xib配置截图:
修复步骤
1. 检查并修复Outlet关联
- 打开对应的Xib文件,找到名为
brickWall的控件,右键点击查看连线列表,确认所有连线都指向InputCollectionViewCell类,且该类的.h文件中存在对应的属性声明:@property (nonatomic, weak) IBOutlet <控件类型,如UIView/UIImageView> *brickWall; - 如果之前删除过该属性但未清除Xib中的连线,直接删除无效的连线即可。
2. 修正Nib加载的Owner参数
当前UIView (NIBLoader)中fromNib方法的owner传的是类对象(self),这会导致KVC关联错误。修改为:
@implementation UIView (NIBLoader) + (instancetype)fromNib { // 加载Nib时owner设为nil,避免不必要的KVC关联 return [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil] firstObject]; } @end
或者在InputCollectionViewCell的loadFromNib方法中直接指定owner为当前实例:
- (void)loadFromNib { UIView *nibView = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil].firstObject; if (nibView) { nibView.frame = self.bounds; nibView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self addSubview:nibView]; nibView.backgroundColor = [UIColor redColor]; } }
3. 修正CollectionView的Cell注册方式
使用Xib创建的Cell,应该注册Nib而非Class,否则CollectionView会用纯代码创建Cell,导致Xib加载逻辑冲突。修改MainViewController的viewDidLoad:
- (void)viewDidLoad { [super viewDidLoad]; // 替换registerClass为registerNib UINib *cellNib = [UINib nibWithNibName:[InputCollectionViewCell identifier] bundle:nil]; [self.menuCollectionView registerNib:cellNib forCellWithReuseIdentifier:[InputCollectionViewCell identifier]]; menuCollectionView.delegate = self; menuCollectionView.dataSource = self; }
同时,移除InputCollectionViewCell中initWithFrame:和initWithCoder:里的[self loadFromNib]调用,因为注册Nib后CollectionView会自动加载Xib创建Cell,重复加载会导致子视图重复添加及KVC错误。
4. 删除手动调用dealloc的代码
viewWillDisappear中的[InputCollectionViewCell dealloc];是错误操作,dealloc由系统自动调用,手动调用会引发内存问题,直接删除该行代码。
内容的提问来源于stack exchange,提问作者Jael Ruvalcaba
相关产品推荐
相关产品推荐

