web-dev-qa-db-ja.com

IB_DESIGNABLEを指定したUIButtonは、ランタイム属性警告をスローし、Interface Builderでレンダリングしません

私はXcode 6.1を実行しており、すでにかなりの数のプロジェクトでIB_DESIGNABLEとIBInspectableを使用していますが、突然すべてが機能しなくなりました。サブクラス化されたボタンを作成して、画像とタイトルを上下に中央に配置し、ユーザーがIBInspectableを使用してIBで境界線の幅と色を設定できるようにしました。

次の警告がログに記録され、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

私はそれが単に警告を投げるだけで何もしない理由を本当に理解していません。私は実際に自分のしたことを変えませんでした。ストーリーボードをチェックしました。iOS7以上で、Xcode 6(最新)で実行することを意図しています。

UIButtonでその値を見つけることができないという不満があり、それをサブクラス化したので少し奇妙です。


更新:だから私は周りのすべてを変更し、それが機能しました。今では、他の何も変更せずに、再びクラップスします。 Xcode 6.1にはバグがあると思います...:/

42
Departamento B

私はライブビューが導入されて以来、広範囲に取り組んできました。最初はXcodeの多くの新機能と同様に、いくつかの欠陥があります。それでも私はそれがとても好きで、新しいバージョンで改善されることを願っています。

原因:

ライブビューは、属性インスペクターを介して設定されるユーザー定義のランタイム属性を介してアプローチできる追加の属性をUIクラスに与える特別なIB_Designableタグを取得する@propertyプロパティで動作します。これらすべてのプロパティが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 永続的な奇妙な問題が発生した場合、ソリューションを徹底的にすることは常に非常に良い考えです。

68
Departamento B

私が個人的にこれを修正した方法:

ユーザー定義のランタイム属性のIDインスペクターで、コードから削除した古いIB_Inspectable要素があることに気づきましたが、まだそこにありました。 -ボタンで削除すると、このエラーがなくなりました。

identityinspector

24

CGFloatの「spacingBetweenLabelAndImage」宣言を「NSNumber」に変更してみてください。

私の知る限り、 setValue: "Cタイプ変数の場合

spacingBetwenLabelAndImage」の宣言をNSNumberに変更するには、少しのコードも変更する必要があります。

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

次のようなものになるかもしれません:

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

(これが最初の行の完全な翻訳であるかどうかは100%確かではありませんが、NSNumberからfloatValueを取得する方法を示したかったのです)

5

私は同様の問題を抱えていましたが、実際にクラスからプロパティを削除しましたが、Interface Builderはまだ見つからないプロパティについて不平を言っていました。

クリーニング、再構築など、多くのことを試しました...しかし、何も機能しませんでした!

本当に解決したのは、ストーリーボードファイルを右クリックし、[開く]、[ソースコード]の順に選択することでした。これにより、エディターでストーリーボードXMLコンテンツが開かれ、セクションが見つかるまで欠落しているプロパティへの参照を検索できました。

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

セクション全体を削除した後、ファイルを保存し、Interface Builderでビューを更新しました。これですべての警告が消えました!

2
rmartinsjr

Departamento Bが提供する方法を使用しましたが、実際には機能しませんでした。ただし、1で問題を修正しました。ストーリーボードからバグのあるビューを選択する2.(エディター-選択したビューをデバッグする)をクリックしてください

1
Martin Z

2つのターゲットがある場合、このエラーが発生しました。 1つは私のメインプロジェクトで、もう1つはターゲットで、デザイン可能なクラスを保持します(ビルドを高速化するため)。
問題は、ストーリーボードにモジュールがないことでした。

enter image description here

0
Nik Kov

すべてのセッターを正しく設定し、プロジェクトに他のSDKをインポートしてこの問題が発生している場合は、[ターゲット-全般]の[リンクされたフレームワークとライブラリ]をチェックしてください。

いくつかのSDKフレームワークを正しくリンクした後、エラーはなくなりました。

0