web-dev-qa-db-fra.com

UIButton avec IB_DESIGNABLE lève un avertissement d'attribut d'exécution et ne s'affiche pas dans Interface Builder

J'utilise Xcode 6.1 et j'utilise IB_DESIGNABLE avec IBInspectable pour déjà pas mal de projets mais tout d'un coup ça ne marche plus. J'ai créé des boutons de sous-classe qui organisent l'image et le titre verticalement centrés les uns sur les autres et permettent à l'utilisateur de définir une largeur et une couleur de bordure via IB avec IBInspectable.

L'avertissement suivant est enregistré et aucun aperçu de mon code n'est disponible dans 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.

Pourtant, le temps d'exécution qu'il rend comme je le voulais et il honore également le même espacement personnalisé que j'ai ajouté via IB.

Voici le code du menubutton qui réorganise le bouton et le titre:

#import "HamburgerButton.h"

IB_DESIGNABLE
@interface HamburgerImageButton : HamburgerButton

@property IBInspectable CGFloat spacingBetweenLabelAndImage;

@end

La mise en oeuvre:

#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

Vous avez probablement remarqué qu'il hérite de HamburgerButton. Ce bouton de hamburger de base n'a pas d'image et ne dessine que la bordure autour du bouton. Ce bouton de hamburger de base a exactement le même problème: il ne dessine pas sa bordure dans drawRect dans IB et il a le même type d'erreurs. Voici ce code par souci d'exhaustivité:

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface HamburgerButton : UIButton

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

@end

La mise en oeuvre:

#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

Je ne comprends pas vraiment pourquoi il lance simplement un avertissement et rien d'autre. Je n'ai pas vraiment changé ce que j'ai fait. J'ai vérifié le storyboard, c'est iOS 7 et plus, destiné à fonctionner dans Xcode 6 (le plus récent).

Il se plaint de ne pas pouvoir trouver cette valeur sur UIButton et c'est un peu bizarre parce que je l'ai sous-classé.


Mise à jour: J'ai donc tout changé et cela a fonctionné. Maintenant, il craque à nouveau, sans rien changer d'autre. Je pense qu'il y a un bug dans Xcode 6.1 ...: /

42
Departamento B

Je travaille beaucoup avec Live Views depuis ses introductions et, comme beaucoup de nouvelles fonctionnalités de Xcode au départ, il a quelques défauts. Je l'aime toujours beaucoup et j'espère qu'il sera amélioré dans les nouvelles versions.

Cause:

Les vues en direct fonctionnent avec les propriétés @property qui obtiennent une balise IB_Designable spéciale qui donnera à la classe d'interface utilisateur des attributs supplémentaires qu'elle peut approcher via des attributs d'exécution définis par l'utilisateur qui seront définis via l'inspecteur d'attributs. Vous verrez que toutes ces propriétés existent également dans l'inspecteur d'identité. La cause première du problème est qu'il ne peut plus mapper ces attributs d'exécution définis par l'utilisateur aux propriétés exposées.

Dès que vous ouvrez un Storyboard ou un xib qui utilise IB_Designable, Xcode recompilera l'écran à chaque changement si vous avez "Actualiser automatiquement les vues" activé. Étant donné que votre code influence également votre interface utilisateur, cela ne doit pas être un changement dans Interface Builder en soi.

Avec des projets plus simples sur des machines plus rapides, cela fonctionne assez bien la plupart du temps. Avec des projets plus importants qui ont également plus d'IB_Designable, le processeur n'a tout simplement pas assez de capacité pour vous suivre et vous obtiendrez une sorte d'erreur de temporisation lors du rendu de l'interface utilisateur. Ceci est la cause de l'avertissement ": IB Designables: ignorer l'attribut d'exécution défini par l'utilisateur pour le chemin de clé" spacingBetweenLabelAndImage "sur l'instance de" UIButton ". Frappez une exception lorsque vous essayez de définir sa valeur: [ setValue: forUndefinedKey:]: cette classe n'est pas conforme au codage de la valeur de clé pour l'espacement de cléBetweenLabelAndImage. " erreur.

Il ne mettra également plus à jour votre interface utilisateur avec votre code personnalisé. Ce n'est pas un problème lorsque vous l'exécutez, car au moment de l'exécution, il reflétera ces modifications.

Une autre cause peut être que votre code ne compile tout simplement pas lorsqu'il essaie de compiler en arrière-plan. Cela est inévitable lorsque vous travaillez sur du code, ce qui le déclenche également fréquemment.

Solution:

Nous devons nous assurer que votre classe de vue personnalisée se compile à nouveau afin que les propriétés puissent être définies avec succès via Interface Builder

  • Dans un storyboard, allez dans "Editeur" dans le menu de la barre supérieure
  • désélectionnez "Actualiser automatiquement les vues" s'il était toujours activé
  • Fermez tous vos onglets de storyboard
  • Reconstruire le projet
  • Corrigez toutes les erreurs de génération, le cas échéant
  • Rouvrez votre storyboard.
  • Allez à nouveau dans "Editeur" et cliquez sur "Actualiser toutes les vues"

Les avertissements devraient avoir disparu et si cela fonctionnait auparavant, vous verrez à nouveau votre code d'affichage personnalisé.

Après un commentaire ci-dessous par sunkas: c'est toujours une très bonne idée de nettoyer votre solution à fond en cas de problèmes étranges qui persistent.

68
Departamento B

Comment j'ai personnellement corrigé cela:

Dans l'inspecteur d'identité dans les attributs d'exécution définis par l'utilisateur, j'ai remarqué que j'avais un ancien élément IB_Inspectable que j'avais supprimé de mon code, mais il était toujours là. Le supprimer avec le bouton - a éliminé cette erreur.

identityinspector

24

Essayez de changer votre déclaration "CGFloat" pour spacingBetweenLabelAndImage en "NSNumber".

Pour autant que je sache, vous ne pouvez pas appeler "setValue: "sur une variable de type C .

Changer la déclaration de "spacingBetwenLabelAndImage" en NSNumber vous obligerait également à changer un peu de code aussi:

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

pourrait devenir quelque chose comme:

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

(Je ne suis pas sûr à 100% s'il s'agit d'une traduction parfaite de la première ligne, mais je voulais montrer comment obtenir un floatValue à partir d'un NSNumber)

5
Michael Dautermann

J'ai eu un problème similaire, mais j'ai en fait supprimé la propriété de la classe et Interface Builder se plaignait toujours de la propriété manquante, difficile.

J'ai essayé beaucoup de choses, comme le nettoyage, la reconstruction ... Mais rien n'a fonctionné!

Ce qui a vraiment été résolu était un clic droit dans le fichier Storyboard, en sélectionnant "Ouvrir en tant que" puis "Code source". Cela a ouvert le contenu XML du storyboard dans l'éditeur et j'ai pu rechercher des références à la propriété manquante jusqu'à ce que je trouve la section:

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

Après avoir supprimé toute la section, j'ai enregistré le fichier et actualisé la vue dans Interface Builder. Maintenant, tous les avertissements ont disparu!

2
rmartinsjr

J'ai utilisé la méthode fournie par Departamento B mais cela n'a pas vraiment fonctionné. Cependant, j'ai résolu mon problème en 1. Sélectionnant les vues de buggy du story-board 2. En cliquant sur (Editeur - Déboguer la vue sélectionnée) J'espère que cela vous aidera

1
Martin Z

J'ai eu cette erreur, quand a deux cibles. Un avec mon projet principal et un autre avec cible, où je détiens des classes à concevoir (pour une construction plus rapide).
Le problème était qu'il manquait un module dans le storyboard.

enter image description here

0
Nik Kov

Si vous êtes sûr d'avoir correctement défini tous les setters, et si vous avez importé d'autres SDK dans votre projet et que vous rencontrez ce problème, cochez "Frameworks et bibliothèques liés" dans Target - General.

Après avoir correctement lié certains frameworks SDK, l'erreur a disparu.

0