68

I know default values of IBInspectable-properties can be set as:

@IBInspectable var propertyName:propertyType = defaultValue in Swift. But how do I achieve a similar effect in Objective-C so that I can have default value of some property set to something in Interface Builder?

Can Poyrazoğlu
  • 33,241
  • 48
  • 191
  • 389
  • 1
    @Fogmeister nope, unfortunately not. I started to think it's not possible, as IB Inspectables are a new feature that came out at the same time with Swift, which supports default values. Since ObjC doesn't support default values, and since it's extremely unlikely for Apple to add such feature to ObjC, I highly doubt it's possible. They could add a Xcode macro (e.g. something like IBDefaultValue) but it would be supporting a legacy language, which I think Apple would be against. – Can Poyrazoğlu Jan 22 '15 at 13:15
  • 1
    OK, thanks for the answer :D Back to the old method for me then. Annoying that you also can't put `UIFont` as an IBInspectable type. I would have thought it possible given that `UILabel` has it. Oh well :) – Fogmeister Jan 22 '15 at 13:19
  • 2
    @Fogmeister yeah it's extremely annoying, however I think it will support more types (looking at you, enums!) and features by time. If you want to add a "font" property, have a look at this: https://github.com/can16358p/CPTutorial/blob/master/CPTutorialBalloon.m (go to line 212) It's a small library that I wrote that accepts a font name in Interface Builder and can dynamically resolve the font name string to an actual font in IB and runtime. Feel free to copy it to your project if it helps. – Can Poyrazoğlu Jan 22 '15 at 13:28
  • Nice, thanks! Will take a look now. – Fogmeister Jan 22 '15 at 13:28
  • Filed as a bug a while back: http://www.openradar.me/19044397 and closed as reproducible/dupe... Dupe master doesn't seem to be on OpenRadar. – jscs Mar 21 '16 at 00:13

5 Answers5

63

Since IBInspectable values are set after initWithCoder: and before awakeFromNib:, you can set the defaults in initWithCoder: method.

@interface MyView : UIView
@property (copy, nonatomic) IBInspectable NSString *myProp;
@property (assign, nonatomic) BOOL createdFromIB;
@end

@implementation MyView

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if(self != nil) {
        self.myProp = @"foo";
        self.createdFromIB = YES;
    }
    return self;
}

- (void)awakeFromNib {
    if (self.createdFromIB) {
        //add anything required in IB-define way
    }
    NSLog(@"%@", self.myProp);
}

@end
WINSergey
  • 1,977
  • 27
  • 39
rintaro
  • 51,423
  • 14
  • 131
  • 139
  • 12
    thank you, but I'm actually looking for a way for the values to be seen by IB. is that possible? – Can Poyrazoğlu Nov 21 '14 at 13:16
  • Sorry but I don't know. – rintaro Nov 21 '14 at 13:42
  • 3
    You just saved my bacon @rintaro. I was trying to set up my custom control with values from IBInspectables during `initWithCoder:` and couldn't figure out why they were all nil. Now I setup my custom control in `awakeFromNib` and everything is fine. Thanks! – user2320861 Oct 14 '15 at 18:40
  • 3
    Thanks for the answer! Also, in order to see the usage implication in the storyboard, you need to implement `- (void)prepareForInterfaceBuilder` that will use the inspectable values to render stuff – ElyashivLavi Oct 29 '17 at 08:41
1

I wrote my code like this. It works pretty well for me, both when designing in the interface builder or running as a app.

@interface MyView : UIView

@property (copy, nonatomic) IBInspectable propertyType *propertyName;

@end

- (void)makeDefaultValues {
    _propertyName = defaultValue;
    //Other properties...
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self makeDefaultValues];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self makeDefaultValues];
    }
    return self;
}
GetToSet
  • 81
  • 2
  • 9
  • Does this allow me to **inspect** the values in Interface Builder, which is exactly what I'm asking. – Can Poyrazoğlu Aug 02 '15 at 12:33
  • You can only see "default" in attributes inspector, but you can see the view drawn with the default values written in the code. – GetToSet Aug 02 '15 at 12:36
  • 1
    Yeah, thanks for the answer, but I already know about that. I'm asking about a solution that enables Inspector to get those default values, just like in Swift. – Can Poyrazoğlu Aug 02 '15 at 12:37
  • Maybe I can't solve this problem, but I think it's not necessary to see the values in inspector since it's already drawn on the view. – GetToSet Aug 02 '15 at 12:40
  • From a programming perspective, I don't need either of them. But while designing (especially handing it to non-tech people to tweak the values) it becomes a problem. – Can Poyrazoğlu Aug 02 '15 at 12:42
1

I'm using like that

@IBInspectable var propertyNameValue:propertyType?
var propertyName:propertyType { return propertyNameValue ?? defaultValue }

if propertyNameValue has nil, propertyName will return defaultValue.

Wanbok Choi
  • 5,432
  • 1
  • 21
  • 26
-1

Why don't use use the macro such as:

#if TARGET_INTERFACE_BUILDER   
// .....IB only specific code when being rendered in IB 
#endif 

???

The prepareForInterfaceBuilder selector may also help you to implement IB specific code.

More info about those 2 points here:
https://developer.apple.com/library/ios/recipes/xcode_help-IB_objects_media/chapters/CreatingaLiveViewofaCustomObject.html

yonel
  • 7,855
  • 2
  • 44
  • 51
  • 2
    does that allow me to see default values in IB inspector, which is exactly what I'm asking? otherwise I know the macros and `prepareForInterfaceBuilder` method. – Can Poyrazoğlu Dec 09 '14 at 00:02
-1

Firstly I tried to override getter and did something like this:

- (UIColor *)borderColor {
    return _borderColor ?: [UIColor greenColor];
}

But in that case I received issue about undeclared identifier _borderColor.

Ok, I tried to avoid this issue via custom getter.

- (UIColor *)getBorderColor {
    return _borderColor ?: [UIColor greenColor];
}

Actually it's not a proper getter, as we don't point this method as getter. In case we point we'll receive issue about undeclared identifier, that's why we won't.

Then we use this method for getting property value in updateUI method.

Also we have to override setter:

- (void)setBorderColor:(UIColor *)borderColor {
  _borderColor = borderColor;
  [self updateUI];
}
kaspartus
  • 1,365
  • 15
  • 33