web-dev-qa-db-fra.com

IBDesignable View Le rendu expire

Je travaille sur une application de temps en temps depuis quelques mois à partir de la première version bêta de XCode 6/iOS 8. L'une de mes fonctionnalités préférées ajoutées est le rendu en direct, rendu possible par la balise @IBDesignable dans Swift.

Je n'ai pas réussi à obtenir une seule chose à vivre rendre. J'ai pensé que cela devait être parce que c'était une version bêta, alors j'ai décidé d'attendre que la version complète soit publiée pour réessayer. Cela a encore échoué. J'ai alors pensé qu'il pourrait y avoir des artefacts de la version bêta dans mon code, alors je l'ai abandonné et j'ai tout recommencé. Cela ne fonctionne toujours pas. Certes, les erreurs sont un peu plus descriptives maintenant.

Voici mon code:

import UIKit

@IBDesignable class MyButton : UIButton {

    let UNPRESSED_COLOR = UIColor(red: 221.0/256.0, green: 249.0/256.0, blue: 14.0/256.0, alpha: 1.0)
    let PRESSED_COLOR = UIColor(red: 166.0/256.0, green: 187.0/156.0, blue: 11.0/256.0, alpha: 1.0)
    var buttonColorValue: UIColor

    let TEXT_COLOR = UIColor(red: 72.0/256.0, green: 160.0/256.0, blue: 5.0/256.0, alpha: 1.0)

    required init(coder: NSCoder) {
        self.buttonColorValue = UNPRESSED_COLOR
        super.init(coder: coder)
        // Initialization code
        self.setTitleColor(TEXT_COLOR, forState: UIControlState.Normal)
        self.setTitleColor(TEXT_COLOR, forState: UIControlState.Highlighted)
        self.setTitleColor(TEXT_COLOR, forState: UIControlState.Selected)
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        super.touchesBegan(touches, withEvent: event)
        buttonColorValue = PRESSED_COLOR
        self.setNeedsDisplay()
    }

    override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
        super.touchesEnded(touches, withEvent: event)
        buttonColorValue = UNPRESSED_COLOR
        self.setNeedsDisplay()
    }

    override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
        super.touchesCancelled(touches, withEvent: event)
        buttonColorValue = UNPRESSED_COLOR
        self.setNeedsDisplay()
    }

    override func drawRect(rect: CGRect) {
        buttonColorValue.setFill()
        let ctx = UIGraphicsGetCurrentContext()
        CGContextFillRect(ctx, rect)
        //UIBezierPath(roundedRect: rect, cornerRadius: 5.0).fill()
    }
}

Voici les erreurs que je reçois lorsque j'essaie de construire avec l'un de ces boutons dans mon story-board:

IB Designables: Failed to update auto layout status: Interface Builder Cocoa Touch Tool crashed

IB Designables: Failed to render instance of MyButton: Rendering the view took longer than 200 ms. Your drawing code may suffer from slow performance.

Comme vous pouvez le constater dans mon code, je voulais au départ que ce bouton soit arrondi. Je pensais que c'était peut-être la raison de ce problème, bien que cela m'ait surpris que Apple conçoive un algorithme de dessin de rectangle arrondi aussi inefficace. Je passai simplement au réglage de la couleur et au dessin du rectangle tel quel. Encore eu des problèmes.

J'imagine (j'espère quand même) qu'il y a une petite chose que je fais mal, parce que j'ai googlé et qu'il n'y a personne d'autre qui semble avoir ce problème. On dirait que cela pourrait être une sorte de boucle infinie?

Ce n'est pas quelque chose qui est nécessaire pour continuer, mais le rendu en direct fonctionnera beaucoup plus rapidement et facilement, car je pourrai voir mes interfaces et les tester sans avoir à les exécuter.

Merci d’avance à tous ceux qui savent comment résoudre ce problème à distance.

25
jchitel

Apparemment, je devais remplacer init(frame: CGRect) avec init(code: NSCoder).

Ça marche! Si quelqu'un pouvait expliquer pourquoi cela ne fonctionnait pas, ce serait formidable. Sinon, je vais bien ici.

49
jchitel

Bien que cela ne soit pas vraiment une réponse utile, j’ai trouvé qu’après avoir cherché une solution à ce problème pendant une demi-heure, une simple fermeture et une réouverture de Xcode s’est révélée être une bonne solution - si vous n’avez pas encore essayé, essayez-le!

6
Nathan Dries

Assurez-vous de substituer prepareForInterfaceBuilder pour résoudre ce problème.

@IBDesignable
class SomeView: UITableView {
 @IBInspectable var something: Int? { didSet { setup() } }

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setup()
}

override init(frame: CGRect, style: UITableViewStyle) {
    super.init(frame: frame, style: style)
    setup()
}

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    setup()
}

func setup() {
    // do sth
}
}
3
konsti

Avait le même problème mais à un coup de œil à ce grand article. Cela a résolu mon problème.

http://nshipster.com/ibinspectable-ibdesignable/

En bref

Pour obtenir ces options dans xcode 

 enter image description here

Faire une propriété comme celle-ci:

@IBInspectable var cornerRadius: CGFloat = 0 {
   didSet {
       layer.cornerRadius = cornerRadius
       layer.masksToBounds = cornerRadius > 0
   }
}
1
Rasmus

Pour moi, cette erreur s'est avérée être due à un appel bloquant à une base de données SQLite (à l'aide de CoreData) dans l'une de mes propriétés @IBInspectable.

À l'origine, mon code interrogeait la base de données, puis utilisait dispatchAsync pour définir la valeur d'une étiquette en fonction des résultats de la requête. Je l'ai modifiée pour que la requête soit également lancée dans le bloc dispatchAsync. L'erreur est immédiatement partie.

Si quelqu'un d'autre a des problèmes avec cette erreur, je suggère de vérifier tout code qui serait exécuté pendant la phase de conception (constructeurs ou propriétés calculées marqués avec @IBInspetable). S'il existe un code bloquant (opérations sur le réseau, accès à la base de données, etc.), cela peut être à l'origine de l'erreur de dépassement de délai. J'espère que cela t'aides.

0
Michael Daw