将 IBoulets 添加到自定义 UIView 子类崩溃“不符合键值”

Posted

技术标签:

【中文标题】将 IBoulets 添加到自定义 UIView 子类崩溃“不符合键值”【英文标题】:Adding IBOulets to custom UIView subclass crashes 'is not key-value compliant' 【发布时间】:2017-04-19 13:52:03 【问题描述】:

我创建了两个不同的子视图EPStudentProgressOpenQuestionEPStudentProgressMultipleChoiceQuestion。它们都继承自 EPStudentProgressQuestion,因为它们的子视图共享一些共同的信息和行为。

每个视图都有自己的 XIB 文件。

EPStudentProgressQuestion里面有如下代码:

#import "EPStudentProgressQuestion.h"

@interface EPStudentProgressQuestion ()

@property (assign, nonatomic) EPStudentProgressQuestionType questiontype;

@end

@implementation EPStudentProgressQuestion

#pragma mark - UIView lifecycle

- (instancetype)initWityQuestionType:(EPStudentProgressQuestionType)questionType 
    self = [super init];

    if (self) 
        self.questiontype = questionType;

        [self setupView];
    

    return self;


- (instancetype)initWithFrame:(CGRect)frame 
    self = [super initWithFrame:frame];

    if (self) 
        [self setupView];
    

    return self;


- (instancetype)initWithCoder:(NSCoder *)aDecoder 
    self = [super initWithCoder:aDecoder];

    if (self) 
        [self setupView];
    

    return self;


#pragma mark - Private methods

- (void)setupView 
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    UIView *view = [[bundle loadNibNamed:[self nibNameForQuestionType] owner:[self class] options:nil] firstObject];
    view.frame = self.bounds;

    [self.layer setCornerRadius:2.f];
    [self.layer setBorderWidth:1.f];
    [self.layer setBorderColor:[UIColor colorWithWhite:232/255.f alpha:1.f].CGColor];
    [self setClipsToBounds:YES];

    [self setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self addSubview:view];


- (NSString*)nibNameForQuestionType 
    switch (self.questiontype) 
        case EPStudentProgressQuestionTypeOpen:
            return @"EPStudentProgressOpenQuestion";

        case EPStudentProgressQuestionTypeMultipleChoice:
            return @"EPStudentProgressMultipleChoiceQuestion";
    

如您所见,非常简单的代码。

如上所述,每个EPStudentProgressQuestion 视图都有自己的XIB 文件,通过Identity Inspector 类连接Files Owner

这是EPStudentProgressOpenQuestion

#import "EPStudentProgressOpenQuestion.h"

@interface EPStudentProgressOpenQuestion ()

@property (weak, nonatomic) IBOutlet UILabel *lblQuestion;

@end

@implementation EPStudentProgressOpenQuestion

@end

EPStudentProgressMultipleChoiceQuestion 完全相同,只是没有任何IBOutlet。但是一旦我为这些视图中的任何一个创建IBOutlets,我就会收到错误... IBOutlet is not key-value compliant...

没有IBOutlets 一切正常。每个视图都正确加载,并且很好地放置在我想要的视图中。但是一旦我将一些 IBOutlets 从 XIB 链接到相应的类,它就会崩溃......

这是崩溃:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<EPStudentProgressQuestion 0x1020196b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key lblQuestion.'

这就是我实例化EPStudentProgressQuestion 视图的方式:

EPStudentProgressOpenQuestion *questionView = [[EPStudentProgressOpenQuestion alloc] initWityQuestionType: EPStudentProgressQuestionTypeOpen];
[self.vQuestionsContainer addSubview:questionView];

知道如何在没有问题的情况下链接IBOutlets吗?

提前谢谢你!!

编辑:

如果我将bundleowner 类更改如下:

NSBundle *bundle = [NSBundle bundleForClass:[EPStudentProgressOpenQuestion class]];
    NSArray *views = [bundle loadNibNamed:[self nibNameForQuestionType] owner:[EPStudentProgressOpenQuestion class] options:nil];
    UIView *view = [views firstObject];

我得到了同样的错误,但我得到了EPStudentProgressOpenQuestion 的错误而不是EPStudentProgressQuestion...

编辑 2: 测试项目链接:https://mega.nz/#!oBhWkawC!RSOzrPOfq_UTVWd3jraRkneuCIyIkS61PKGeca2Bilc

【问题讨论】:

请编辑您的问题以包括 (1) 您的 IBOutlet 声明和 (2) 您收到的完整错误消息。 @robmayoff 完成,抱歉! 你能展示你在 xib 中实例化视图控制器的代码吗? 您的错误消息表明您正在加载类型为 EPStudentProgressOpenQuestion 的对象,它既不是 QuestionViewOne 也不是 QuestionViewTwo 由于您在没有告诉我们的情况下更改了详细信息,因此我们目前无法知道您是否不小心更改了实际上是导致问题的原因。 【参考方案1】:

让你崩溃的问题是你传递[self class] 而不仅仅是self 作为笔尖所有者。将您的笔尖加载线更改为:

NSArray *views = [bundle loadNibNamed:[self nibNameForQuestionType] owner:self options:nil];

您还有另一个问题是您要加载笔尖两次。在initWityQuestionType: 中,您调用[super init]。你没有意识到的是-[UIView init] 调用[self initWithFrame:CGRectZero]。因此,您最终调用了覆盖的initWithFrame:,它调用了setupView。然后当它返回到initWityQuestionType: 时,也会调用setupView

我建议您完全摆脱 initWithFrame: 覆盖。

【讨论】:

谢谢!!我的天啊,我很快就写了那段代码,我犯了那个愚蠢的错误……而且我不知道UIView init 的那件事。再次感谢您!【参考方案2】:

您的崩溃表明EPStudentProgressQuestion(您的超类)不符合键值对。这意味着在您访问 IBOutlet 时,您会引用 EPStudentProgressQuestion 而不是 EPStudentProgressOpenQuestionEPStudentProgressMultipleChoiceQuestion

只需检查您使用新 IBOutlets 的代码,然后更改其中使用的变量的类型或将转换添加到正确的类。

【讨论】:

我编辑了问题,您可以看到它在加载 bundleownerself 时也会崩溃,我为 EPStudentProgressOpenQuestion 加载了一个。此外,我不使用 IBOutlet,只是创建它(XIB 和 .h 或 .m 之间的链接)会使应用程序崩溃。 我已经将一个只有这 3 个类的示例项目上传到 MEGA。有问题的下载链接。如果您使用可用的IBOutlet 添加关系,它将崩溃。现在它不会崩溃。【参考方案3】:

您的视图控制器可能在您的 xib 中有错误的类。请更改 UIView 类名,而不是像图片一样在 File's Owner 中

您还调用了 [self setup] 方法:

- (instancetype)initWityQuestionType:(EPStudentProgressQuestionType)questionType 
    self = [super init];
    if (self) 
        self.questiontype = questionType;
        [self setupView];
    
    return self;

你不需要再次调用它

- (instancetype)initWithFrame:(CGRect)frame 
 

- (instancetype)initWithCoder:(NSCoder *)aDecoder 

它正在创建一个初始化循环并导致内存泄漏。

【讨论】:

我想我已经设置了正确的类。 EPStudentProgressOpenQuestion.xib -> File's Owner -> Identity Inspector -> Class 设置为 EPStudentProgressOpenQuestionEPStudentProgressMultipleChoiceQuestion.xib 相同,但 Class 设置为 EPStudentProgressMultipleChoiceQuestion

以上是关于将 IBoulets 添加到自定义 UIView 子类崩溃“不符合键值”的主要内容,如果未能解决你的问题,请参考以下文章

使用 xib 将 tapGestureRecognizer 添加到自定义 UIView

将 xib 中的子视图添加到自定义 UIView

是否可以将 GestureRecognizer 添加到自定义 UIView 子视图中的标签

xcode - 将 xib 文件附加到自定义 UIView 类时出错

iOS 7 - 自定义 UIView 的动态壁纸行为

将视频添加到自定义照片集合返回错误