带有IB_DESIGNABLE的UIButton会抛出运行时属性警告,并且不会在Interface Builder中呈现

Dep*_*o B 42 objective-c interface-builder uibutton ios xcode6

我正在运行Xcode 6.1并且我已经在IBInspectable中使用IB_DESIGNABLE用于很多项目,但突然之间它就不再起作用了.我创建了子类按钮,将图像和标题垂直居中放置,使用户可以通过IBI使用IBInspectable设置边框宽度和颜色.

将记录以下警告,并且我无法在drawRect中预览我的代码:

warning: IB Designables: Ignoring user defined runtime attribute for key path "spacingBetweenLabelAndImage" on instance of "UIButton". Hit an exception when attempting to set its value: [<UIButton 0x7f9278591260> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key spacingBetweenLabelAndImage.
Run Code Online (Sandbox Code Playgroud)

仍然,运行时它渲染像我打算渲染它,它也尊重我通过IB添加的相同自定义间距.

这是重新排列按钮和标题的menubutton的代码:

#import "HamburgerButton.h"

IB_DESIGNABLE
@interface HamburgerImageButton : HamburgerButton

@property IBInspectable CGFloat spacingBetweenLabelAndImage;

@end
Run Code Online (Sandbox Code Playgroud)

执行:

#import "HamburgerImageButton.h"

@implementation HamburgerImageButton

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGSize imageSize = self.imageView.frame.size;
    CGSize titleSize = self.titleLabel.frame.size;

    // Move the label left and the image right by half the width
    CGFloat leftInset = titleSize.width / 2;
    CGFloat rightInset = imageSize.width / 2;

    CGFloat halfSpacing = self.spacingBetweenLabelAndImage == 0 ? 0 : self.spacingBetweenLabelAndImage / 2;

    CGFloat topInset = imageSize.height / 2 + halfSpacing;
    CGFloat bottomInset = titleSize.height / 2 + halfSpacing;

    UIEdgeInsets imageInsets = UIEdgeInsetsMake(-bottomInset, leftInset, bottomInset, -leftInset);
    UIEdgeInsets titleInsets = UIEdgeInsetsMake(topInset, -rightInset, -topInset, rightInset);
    self.imageEdgeInsets = imageInsets;
    self.titleEdgeInsets = titleInsets;
}

@end
Run Code Online (Sandbox Code Playgroud)

您可能已经注意到它继承了HamburgerButton.这个基本的汉堡包按钮没有图像,只绘制按钮周围的边框.这个基本的汉堡包按钮有完全相同的问题:它不会在IB中的drawRect中绘制它的边框,并且它具有相同类型的错误.为了完整起见,这是代码:

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface HamburgerButton : UIButton

@property IBInspectable CGFloat borderWidth;
@property IBInspectable UIColor *borderColor;

@end
Run Code Online (Sandbox Code Playgroud)

执行:

#import "HamburgerButton.h"
#import <QuartzCore/QuartzCore.h>

@implementation HamburgerButton

- (void)copyInspectables {
    self.layer.borderWidth = self.borderWidth;
    self.layer.borderColor = self.borderColor.CGColor;
}

- (void)drawRect:(CGRect)rect {
    [self copyInspectables];
}

@end
Run Code Online (Sandbox Code Playgroud)

我真的不明白为什么它只是抛出警告而没有别的.我并没有真正改变我的所作所为.我已经检查了故事板,它是iOS 7及更高版本,意味着可以在Xcode 6(最新版本)中运行.

它抱怨无法在UIButton上找到这个值,这有点奇怪,因为我已将其子类化了.


更新:所以我改变了一切,并且它有效.现在它再次扯掉,没有改变任何其他东西.我认为Xcode 6.1中存在一个错误......:/

Dep*_*o B 70

我一直在使用Live Views进行广泛的工作,因为它的介绍和最初Xcode中的许多新功能一样,它有一些缺陷.我仍然喜欢它,我希望它能在新版本中得到改进.

原因:

实时视图与@property属性一起使用,这些属性获得一个特殊的IB_Designable标记,该标记将为UI类提供额外的属性,它可以通过属性检查器设置的用户定义的运行时属性来处理.您将看到Identity Inspector中也存在所有这些属性.问题的根本原因是它无法将这些用户定义的运行时属性映射到暴露的属性.

一旦打开使用IB_Designable的Storyboard或xib,如果您打开了"自动刷新视图",Xcode将在每次更改时重新编译屏幕.由于您的代码也会影响您的UI,因此不必在Interface Builder本身进行更改.

通过更快的机器上的简单项目,这在大多数情况下都能很好地工作.对于具有更多IB_Designable的较大项目,CPU根本没有足够的容量来跟上你,并且在渲染UI时会出现一种超时错误.这是"警告:IB Designables:在"UIButton"实例上忽略键路径"spacingBetweenLabelAndImage"的用户定义的运行时属性的原因.尝试设置其值时遇到异常:[setValue:forUndefinedKey:]:此类是密钥间隔不是密码值编码兼容的间隔.BetweenLabelAndImage." 错误.

它也不会再使用您的自定义代码更新您的UI.但是,当您运行它时,这不是问题,因为在运行时它将反映这些更改.

另一个原因可能是您的代码在尝试在后台编译时根本无法编译.当您处理代码时,这是不可避免的,因此也会频繁触发代码.

解:

我们需要确保您的自定义视图类再次编译,以便可以通过Interface Builder成功设置属性

  • 在故事板中,转到顶部栏菜单中的"编辑器"
  • 如果仍然打开,请取消选择"自动刷新视图"
  • 关闭所有故事板选项卡
  • 重建项目
  • 修复所有构建错误(如果有)
  • 重新打开故事板.
  • 再次转到"编辑器"并单击"刷新所有视图"

警告应该消失,如果有效,您将再次看到自定义视图代码.

在sunkas发表评论之后:如果出现任何奇怪的问题,彻底清理您的解决方案总是一个非常好的主意.

  • 首先,它对我不起作用.第二次在重建项目后清理并重新启动时它起作用了 (4认同)

Han*_*ney 24

我个人如何解决这个问题:

在用户定义的运行时属性的身份检查器中,我注意到我有一个旧的IB_Inspectable元素,我已从我的代码中删除,但它仍然在那里.用 - 按钮删除它摆脱了这个错误.

identityinspector


Mic*_*ann 5

尝试将" CGFloat"声明更改spacingBetweenLabelAndImage为" NSNumber".

据我所知,你不能setValue:在C型变量上调用" ".

将" spacingBetwenLabelAndImage" 的声明更改为NSNumber也需要您更改一些代码:

CGFloat halfSpacing = self.spacingBetweenLabelAndImage == 0 ? 0 : self.spacingBetweenLabelAndImage / 2;
Run Code Online (Sandbox Code Playgroud)

可能会成为:

CGFloat halfSpacing = (self.spacingBetweenLabelAndImage ? ([self.spacingBetweenLabelAndImage floatValue] / 2) : 0.0);
Run Code Online (Sandbox Code Playgroud)

(我不是100%肯定,如果这是第一行的完美翻译,但我想展示如何从NSNumber中获取floatValue)