我正在运行 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
我真的不明白为什么它只是发出警告而没有别的。我并没有真正改变我所做的。我检查了 Storyboard,它是 iOS 7 及更高版本,旨在在 Xcode 6(最新)中运行。
它提示无法在 UIButton 上找到该值,这有点奇怪,因为我已经对它进行了子类化。
更新: 所以我改变了周围的一切,它奏效了。现在它再次出现,没有改变任何其他东西。我认为 Xcode 6.1 中存在错误...:/
最佳答案
自从 Live Views 推出以来,我一直在广泛使用它,并且与 Xcode 中最初的许多新功能一样,它也存在一些缺陷。我还是很喜欢它,我希望它会在新版本中得到改进。
原因:
实时 View 与@property 属性一起使用,这些属性获得一个特殊的 IB_Designable 标记,该标记将为 UI 类提供额外的属性,它可以通过用户定义的运行时属性访问,这些属性将通过属性检查器设置。您将看到所有这些属性也存在于 Identity Inspector 中。问题的根本原因是它无法再将那些用户定义的运行时属性映射到公开的属性。
一旦您打开使用 IB_Designable 的 Storyboard 或 xib,如果您打开了“自动刷新 View ”,Xcode 将在每次更改时重新编译屏幕。由于您的代码也会影响您的 UI,因此不必更改 Interface Builder 本身。
在更快的机器上进行更简单的项目,这在大多数情况下都能很好地工作。对于具有更多 IB_Designable 的大型项目,CPU 根本没有足够的能力跟上您的速度,并且您在渲染 UI 时会遇到一种超时错误。这是 “警告的原因:IB Designables:忽略“UIButton”实例上键路径“spacingBetweenLabelAndImage”的用户定义运行时属性。尝试设置其值时遇到异常:[setValue:forUndefinedKey:]:此类与键间距BetweenLabelAndImage 的键值编码不兼容。” 错误。
它也不会再使用您的自定义代码更新您的 UI。但是,当您运行它时,这不是问题,因为在运行时它会反射(reflect)这些更改。
另一个原因可能是您的代码在尝试在后台编译时根本无法编译。当您处理代码时,这是不可避免的,因此也会频繁触发它。
解决方案:
我们需要确保您的自定义 View 类再次编译,以便可以通过 Interface Builder 成功设置属性
- 在 Storyboard中,转到顶部栏菜单中的“编辑器”
- 如果“自动刷新 View ”仍处于开启状态,请取消选择它
- 关闭所有 Storyboard标签
- 重建项目
- 修复所有构建错误(如果有)
- 重新打开您的 Storyboard。
- 再次进入“编辑器”,点击“刷新所有 View ”
警告应该消失,如果它在您再次看到您的自定义 View 代码之前有效。
sunkas 在下面发表评论后:clean 总是一个好主意如果出现任何持续存在的奇怪问题,请彻底解决您的问题。
关于ios - 带有 IB_DESIGNABLE 的 UIButton 会引发运行时属性警告,并且不会在 Interface Builder 中呈现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26656400/