IBDesignable View Rendering times out

jchitel picture jchitel · Nov 6, 2014 · Viewed 9.9k times · Source

I've been working on an app on and off for a few months starting with the first XCode 6/iOS 8 beta release. One of my favorite features added is live rendering, made possible with the @IBDesignable tag in Swift.

I haven't been able to get a single thing to live render. I figured that must have been because it was a beta release, so I decided to wait for the full release to come out to try again. It still failed. I figured then that there might be artifacts from the beta releases in my code, so I scrapped it and started fresh. It still doesn't work. Granted, the errors are slightly more descriptive now.

Here is my 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()
    }
}

Here are the errors I get when I try to build with one of these buttons in my storyboard:

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.

As you can see in my code, I originally wanted this button to be rounded. I figured this might be the reason for this problem, though it surprised me that Apple would design a rounded rectangle drawing algorithm that inefficient. I switched to simply setting the color and drawing the rectangle as-is. Still had problems.

I figure (I hope, anyway) that there is one small thing that I'm doing wrong, because I've googled and there is no one else that seems to have this problem. Seems like it might be some kind of infinite loop?

It's not something that's necessary for me to continue, but getting live rendering to work will make development a lot faster and easier for me, because I will be able to see my interfaces and test them without having to run them.

Thanks in advance to anyone who has a remote clue on how to solve this.

Answer

jchitel picture jchitel · Nov 6, 2014

Apparently I needed to override init(frame: CGRect) along with init(code: NSCoder).

Got it working! If anyone could care to explain why this wasn't working, that would be great. Otherwise, I'm fine here.