Xcode 6: Loving the IB-Renderable Views

Despite my tendency to do most things in code, this stuff is really amazing. Here’s my quick “how-to”, followed by sample code, followed by a few final thoughts.

  1. Create app (I used single view)
  2. Select the app, in TARGETS, add a new Framework & Library > Cocoa Touch Framework target, e.g. CustomViews
  3. Add the .h/.m files to your project, making sure the framework box is checked and not the app one.
  4. Drag a view into your main storyboard. Color the background so you can see it, and adjust its size.
  5. With the view selected, open the Identity inspector. Change the Custom Class > Class to your class name. For example, TestView as in the following code.
  6. Switch to the attributes inspector and adjust the border color, width, and corner radius. The view should update in real time.
  7. Save. Compile. Run.
#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface TestView : UIView
@property (nonatomic) IBInspectable UIColor *borderColor;
@property (nonatomic) IBInspectable NSInteger borderWidth;
@property (nonatomic) IBInspectable NSInteger cornerRadius;
@end

@implementation TestView
- (instancetype) initWithFrame:(CGRect)frame
{
    if (!(self = [super initWithFrame:frame])) return self;
    _borderColor = [UIColor blackColor];
    _borderWidth = 0;
    _cornerRadius = 0;
    
    return self;
}

- (void) setBorderColor:(UIColor *)borderColor
{
    _borderColor = borderColor;
    self.layer.borderColor = _borderColor.CGColor;
}

- (void) setBorderWidth:(NSInteger)borderWidth
{
    _borderWidth = borderWidth;
    self.layer.borderWidth = _borderWidth;
}

- (void) setCornerRadius:(NSInteger)cornerRadius
{
    _cornerRadius = cornerRadius;
    self.layer.cornerRadius = cornerRadius;
}
@end

Key things to notice:

  • The IB_DESIGNABLE keyword before the subclass interface declaration
  • The IBInspectable keywords for the items that show up in the attributes inspector

Beyond that, be aware that the frame is constantly being redrawn. Although you don’t have to use drawRect:, despite what the docs show, you can add live feedback by updating the text for labels or using string drawing in a custom drawRect: routine. Use the TARGET_INTERFACE_BUILDER target test if you want to comment that stuff out for any other use, though. Auto Layout is available both in code for building up the view and in IB for coordinating this view with other views in storyboards and nibs with this stuff. Views don’t have to be simple like this example. You can add subviews and they’ll show up just fine, both in execution and in IB. Although you can’t interact with any controls (for example, buttons or switches) that you add as subviews in your class definition file,  you can connect them to action targets in IB.

One Comment

  • Didn’t manage it : framework compiles on every save inthe framework class but immediately generates 2 errors (using iOS as target for app):

    1) file:///Main.storyboard: error: IB Designables: Failed to update auto layout status: dlopen(components.framework, 1): no suitable image found. Did find: components.framework: mach-o, but wrong architecture

    2) file:///Main.storyboard: error: IB Designables: Failed to render instance of compview: dlopen(components.framework, 1): no suitable image found. Did find: components.framework: mach-o, but wrong architecture

    and view remains white (can’t be generated for use in storyboard). Adding i386 and x86_64 architectures to framework target didn’t help either. What I’m missing?