IBDesignable View Rendering times out

2019-01-22 18:40发布

问题:

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.

回答1:

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.



回答2:

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!



回答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
}
}


回答4:

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

Make a property like this:

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


回答5:

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.