【问题标题】:UIButton with IB_DESIGNABLE throws runtime attribute warning and does not render in Interface Builder带有 IB_DESIGNABLE 的 UIButton 会引发运行时属性警告,并且不会在 Interface Builder 中呈现
【发布时间】:2014-12-26 16:40:48
【问题描述】:

我正在运行 Xcode 6.1,并且我已经在很多项目中使用 IB_DESIGNABLE 和 IBInspectable,但突然之间它就不再工作了。我创建了子类按钮,这些按钮将图像和标题垂直居中排列,并允许用户通过 IB 使用 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.

不过,它呈现的运行时就像我希望它呈现的那样,它还尊重我通过 IB 添加的相同自定义间距。

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

#import "HamburgerButton.h"

IB_DESIGNABLE
@interface HamburgerImageButton : HamburgerButton

@property IBInspectable CGFloat spacingBetweenLabelAndImage;

@end

实施:

#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

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

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface HamburgerButton : UIButton

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

@end

实施:

#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

我真的不明白为什么它只是发出警告而没有别的。我并没有真正改变我所做的。我检查了故事板,它是 iOS 7 及更高版本,旨在在 Xcode 6(最新)中运行。

它抱怨无法在 UIButton 上找到该值,这有点奇怪,因为我已经对它进行了子类化。


更新: 所以我改变了周围的一切,它奏效了。现在它再次出现,没有改变任何其他东西。我认为 Xcode 6.1 中存在错误...:/

【问题讨论】:

  • 请注意,(2017) 在某些情况中,通过单击“编辑器 -> 刷新所有视图”并让它完全运行即可非常简单地解决此问题.请注意,这些天(2017 年)当然基本上不可能使用 Xcode,除非您使用“关闭自动刷新”技巧...explanation...特别是如果您这样做,您有时会收到警告问题在这里,你只需要“刷新”并让它运行。

标签: ios objective-c uibutton interface-builder xcode6


【解决方案1】:

自从 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 在下面发表评论后:如果有任何奇怪的问题持续存在,请彻底clean 解决您的解决方案总是一个好主意。

【讨论】:

  • 首先它对我不起作用。当我在重建项目后清理并重新启动时,它第二次起作用了
  • 感谢 Sunkas,我将添加您的步骤以确保。自从我处理这个问题以来已经有一段时间了,我现在通常只根据要求渲染。
  • 这仍然困扰着我 - 如果我退出并重新启动 Xcode,我会收到错误消息。我发现关闭故事板同时保持 Xcode 项目打开,在模拟器上运行,然后打开故事板通常可以修复它。
  • 谢谢。清理“DeriveDate”后,这对我有用。
  • 这是非常有用且很棒的答案:)
【解决方案2】:

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

在用户定义的运行时属性的身份检查器中,我注意到我有一个旧的 IB_Inspectable 元素已从我的代码中删除,但它仍然存在。使用 - 按钮删除它可以消除此错误。

【讨论】:

  • 很好,它可以消除错误但又出现了,所以这是Xcode的一个错误。
【解决方案3】:

尝试将 spacingBetweenLabelAndImage 的“CGFloat”声明更改为“NSNumber”。

据我所知,you can't call "setValue:" on a C-type variable

将“spacingBetwenLabelAndImage”的声明更改为 NSNumber 还需要您更改一些代码:

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

可能会变成这样:

CGFloat halfSpacing = (self.spacingBetweenLabelAndImage ? ([self.spacingBetweenLabelAndImage floatValue] / 2) : 0.0);

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

【讨论】:

  • 当我听从你的建议时会发生什么非常有趣。警告消失了,但我不能再通过 IB 设置它。 weheartswift.com/… CGFloat 在这里标记为尽可能。
  • 好的,所以将其更改为 float 而不是 CGFloat 会显示 Interface Builder 中的边框。你至少让我走上了正轨!它仍然不尊重更新的 UIEdgeInsets。如果您将答案更新为 float 而不是 NSNumber 我会接受它作为答案。
  • captechconsulting.com/blog/jack-cox/… 所以 UIEdgeInsets 不是 IB_DESIGNABLE - 你可以把它包起来!
  • @DepartamentoB 您是否设法让 IBInspectable NSNumber 显示在界面构建器中?我在这里遇到了类似的问题。
  • 不要认为 NSNumber 有效,它是各种数字的包装类。只需使用最接近您想要的类型并在需要时将其转换为 NSNumber。
【解决方案4】:

我遇到了类似的问题,但实际上我从类中删除了该属性,并且 Interface Builder 仍在抱怨缺少属性,很难。

尝试了很多事情,比如清洁、重建……但没有任何效果!

真正解决的问题是右键单击 Storyboard 文件,选择“打开方式”,然后选择“源代码”。这在编辑器中打开了故事板 XML 内容,我能够查找对缺失属性的引用,直到找到该部分:

<userDefinedRuntimeAttributes>
    <userDefinedRuntimeAttribute... keyPath="My Missing Property Name">
    ...
</userDefinedRuntimeAttributes>

删除整个部分后,我保存了文件并在 Interface Builder 中刷新了视图。现在所有警告都消失了!

【讨论】:

  • 这很好用。它实际上解决的不仅仅是警告,现在我的图像也显示出来了。
【解决方案5】:

我使用了 Departamento B 提供的方法,但它并没有真正奏效。但是,我通过以下方式解决了我的问题 1.从故事板中选择错误视图 2.单击(编辑器 - 调试选定视图) 希望这会有所帮助

【讨论】:

  • 谢谢,由于性能问题,已经有一段时间没有使用实时视图了。我猜调试选择的视图也会触发某种重新编译?顺便问一下,您使用的是哪个版本的 Xcode?​​span>
【解决方案6】:

如果您确定所有设置器都正确设置,并且您在项目中导入了其他一些 SDK 并且遇到此问题, 检查 Target - General 中的“链接框架和库”。

在我正确链接了一些 SDK 框架后,错误就消失了。

【讨论】:

    【解决方案7】:

    我有这个错误,当有两个目标时。一个是我的主要项目,另一个是目标,我在其中持有可设计的类(以便更快地构建)。
    问题是情节提要中缺少一个模块。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多