View Controller:如何正确初始化依赖于NIB的值

时间:2014-06-25 05:28:01

标签: ios objective-c uiviewcontroller

我想知道最好的方法是初始化依赖于NIB中对象的值。例如,假设我有UIView获得自定义cornerRadiusborderColor

现在我做的是

@interface MyViewController ()
@property (nonatomic, weak) IBOutlet UIView *roundyView;
@end

@implementation MyViewController

- (id)initWithNibName:(NSString *)nibNameOrNil 
               bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // (!) Can't assign to roundyView, hasn't been loaded from NIB yet
        // ...
    }
    return self;
}

-(void)viewDidLoad {
    // Ahh, NIB loaded, roundyView has a value
    self.roundyView.layer.cornerRadius = 5.0f;
    self.roundyView.layer.borderColor = [UIColor redColor].CGColor;
}

@end

到目前为止,这么好。接下来我添加一个setter,这样我就可以从程序的其他地方更改边框颜色。

@property (nonatomic, strong) UIColor *roundBorderColor;

并且

-(void)setRoundBorderColor:(UIColor*)roundBorderColor {
    _roundBorderColor = roundBorderColor;
    self.roundyView.layer.borderColor = roundBorderColor.CGColor;
}

问题是我通常在实例化类时调用该访问器,但在它出现之前。像

这样的东西
MyViewController *vc = [[MyViewController alloc] initWithNibName:@"MyViewController" 
                                                          bundle:nil];
// Setting the color, NIB hasn't loaded though (!)
vc.roundBorderColor = [UIColor yellowColor];
[self presentViewController:vc animated:YES completion:nil];

这不起作用,因为setter在viewDidLoad之前运行。所以相反,我通常会这样说:

-(void)viewDidLoad {
    // ...
    if (_roundBorderColor != nil) {
        // The setter was already called somewhere,
        // call it again now that we have the NIB
        [self setRoundBorderColor:_roundBorderColor];
    }
}

有没有更清洁的方法来解决这个问题?

4 个答案:

答案 0 :(得分:1)

转到Interface Builder中的身份检查器(界面构建器视图中左起第三个选项),并为您的视图设置"用户定义的运行时属性"并添加以下内容:
Keypath:layer.cornerRadius值:数字,5。
不幸的是 - 这似乎不适用于边框颜色,因为UI只允许"颜色"但不是CGColor 保持代码清洁颜色的简单方法是将用户定义的属性设置为视图控制器并通过笔尖设置。 在您的视图控制器中:

@property (nonatomic,strong) UIColor* borderColor;

然后在界面构建器中,通过用户定义的运行时属性将颜色设置为您想要的颜色 然后将颜色设置为viewDidLoad中图层的边框 涉及一些代码而不仅仅是UI Builder,但至少不需要在代码中指定颜色。

或者,如果您只是想使用代码设置颜色而不想等待" viewDidLoad"你可以这样做:

-(void)setRoundBorderColor:(UIColor*)roundBorderColor {
    [self view]; // force view load from nib
    self.roundyView.layer.borderColor = roundBorderColor.CGColor;
}

答案 1 :(得分:1)

通过使用IBInspectable功能从Xcode 6开始优雅地解决了这个问题。例如,在UIButton子类中:

@IBInspectable var borderColor : UIColor? {
    get {
        let cg = self.layer.borderColor
        return cg == nil ? nil : UIColor(CGColor: cg!)
    }
    set {
        self.layer.borderColor = newValue?.CGColor ?? nil
    }
}

storyboard / xib中此按钮的实例现在在“属性”检查器中显示“borderColor”颜色弹出菜单。

enter image description here

这设置了一个UIColor,但我们的属性只是图层borderColor的一个外观,并在UIColor和CGColor之间进行转换。

答案 2 :(得分:0)

通过在initWithNibName初始化您的属性,您可以使其更清洁一点 - 这样您就可以安全地访问viewDidLoad中的属性而无需检查。

-(id)initWithNibName:(NSString *)nibNameOrNil 
               bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        _roundBorderColor = [UIColor redColor];
    }
    return self;
}

-(void)viewDidLoad {
// ...

    [self setRoundBorderColor:_roundBorderColor];
}

答案 3 :(得分:0)

您应该使用 isViewLoaded 方法。

- (void)setRoundBorderColor:(UIColor *)roundBorderColor {
    _roundBorderColor = roundBorderColor;

    // would be launched only if view is initialised
    if ([self isViewLoaded]) {
        self.roundyView.layer.borderColor = roundBorderColor.CGColor;
    }
}

- (void)setBorderRagius:... // same idea as before

- (void)viewDidLoad {
    self.roundyView.layer.cornerRadius = self.cornerRadius;
    self.roundyView.layer.borderColor = self.borderColor;
}

您需要将一些默认值设置为 cornerRadius borderColor 属性。如果要设置 nil 值,则不执行任何操作。