IBDesignable View Rendering times out
Asked Answered
G

5

25

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.

Galvez answered 6/11, 2014 at 6:3 Comment(0)
G
49

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.

Galvez answered 6/11, 2014 at 6:19 Comment(6)
According to other posts I've read, live rendering doesn't call init(code: NSCoder) at all -- just init(frame: CGRect)Higgler
Overriding init(frame: CGRect) , init(code: NSCoder) and init() did help me too.How
Hah, no wonder! Thanks man, this solved my problem too. Wonder why Apple don't make init(frame: CGRect) a required override as well.Harte
This should probably be marked as the answer, as it seems to be the fix for most people. Fixed my issue right away.Contrite
Apart from this you should check if there are any uninitialized variables you're using in drawRect as this causes this problem too.Ioab
I dont think so that is the fix. I am on 7.2 and I have both methods and its not working. I am still looking for real reasonFinesse
R
6

Although this might not really be a helpful answer, I found that after looking for a solution for this for half an hour a simple close and re-open of Xcode did the trick - if you haven't tried this yet give it a go!

Redhot answered 22/3, 2015 at 23:43 Comment(0)
C
3

Make sure you override prepareForInterfaceBuilder to solve this.

@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
}
}
Crosley answered 12/5, 2016 at 13:26 Comment(0)
S
1

Had the same problem but to a glance at this great article. It solved my problem.

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

In short

To get these options in xcode

enter image description here

Make a property like this:

@IBInspectable var cornerRadius: CGFloat = 0 {
   didSet {
       layer.cornerRadius = cornerRadius
       layer.masksToBounds = cornerRadius > 0
   }
}
Stepson answered 10/8, 2015 at 20:45 Comment(0)
B
0

For me, this error turned out to be due to a blocking call to a sqlite database (using CoreData) in one of my @IBInspectable properties.

My code originally queried the database and then used dispatchAsync to set the value of a label based on the results of the query. I changed it so that the query was also launched in the dispatchAsync block. The error immediately went away.

If anyone else is having trouble with this error, I suggest checking out any code that would be executed during the design phase (constructors or computed properties marked with @IBInspetable). If there is any blocking code (network operations, database access, etc.), it might be causing the timeout error. Hope this helps.

Brink answered 10/3, 2015 at 22:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.