来自另一个UIViewController的nib中的nib的自定义UIView - IBOutlets是nil

时间:2013-11-16 03:49:24

标签: ios objective-c uiview uiviewcontroller

我正在尝试创建一个自定义UIView,它保存对自己的IBOutlets的引用。然后我想将这个自定义UIView放入另一个笔尖。

我在自定义UIView的awakeFromNib方法中做了一些额外的逻辑。不幸的是,当我尝试访问IBOutlets中的awakeFromNib时,它们是零。

以下是设置:

  1. 我有一个UIView子类CustomView
  2. 我有一个包含三个子视图的自定义.xib文件
  3. 在另一个nib(属于视图控制器)中,我将UIView拖到视图上,然后将自定义类更改为CustomView
  4. 我尝试将IB中的CustomView笔尖中的视图设置为自定义类CustomView并将IBOutlets连接到视图,但它们仍为零。
  5. 我尝试将文件所有者设置为CustomView并将IBOutlets连接到文件的所有者,但它们仍为零。
  6. 我还尝试使用其他IBOutlet UIView *view,然后将其作为子视图添加到self中的awakeFromNib,但也没有做任何事情。
  7. 以下是代码:

    // CustomView.h
    @interface CustomView : UIView
    
    @property (nonatomic, retain) IBOutlet UITextField *textField;
    @property (nonatomic, retain) IBOutlet UIView *subview1;
    @property (nonatomic, retain) IBOutlet UIView *subview2;
    
    // CustomView.m
    @implementation CustomView
    @synthesize textField, subview1, subview2; 
    
    - (id)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        }
        return self;
    }
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
    
        if (self) {
        }
        return self;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        [self setup];
    }
    
    - (void)setup {
        // Fails because self.textField is nil
        self.textField.text = @"foo";
    }
    

3 个答案:

答案 0 :(得分:20)

我最终使用了最新编辑here中的步骤,并且效果很好。

您使用普通UIView作为xib中的顶级视图。

然后将文件所有者设置为自定义子类(CustomView)。

最后,添加一行:

[self addSubview:[[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0]];

位于if (self != nil)initWithCoder的{​​{1}}块中。

瞧! initWithFrame已经联系起来并准备好在通话结束后继续。对解决方案非常满意,但是很难挖掘出来。

希望这有助于其他任何人。


编辑:我将链接更新为尚未死亡的链接。由于我从未拼写过完整的代码,因此修改后的内容如下:

IBOutlets

这种模式已经变得非常普遍,我实际上在名为- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { UIView *nib = [[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0]; [self addSubview:nib]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { UIView *nib = [[[UINib nibWithNibName:@"CustomView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0]; [self addSubview:nib]; } return self; } - (void)awakeFromNib { [super awakeFromNib]; [self setup]; } - (void)setup { // Doesn't fail because life is awesome self.textField.text = @"foo"; } 的{​​{1}}上创建了一个类别,它实现了以下方法:

UIView

所以上面的代码可以简化为:

UIView+Nib

另请注意,上述代码可以进行更多重构,因为+ (UIView *)viewWithNibName:(NSString *)nibName owner:(id)owner { return [[[UINib nibWithNibName:nibName bundle:nil] instantiateWithOwner:owner options:nil] objectAtIndex:0]; } [self addSubview:[UIView viewWithNibName:@"CustomView" owner:self]]; 中的逻辑完全相同。希望有所帮助!

答案 1 :(得分:1)

我假设XIB的结构是这样的

CustomView.xib
    CustomView
        UITextField -> linked to IBOutlet textField
        other views

CustomViewController.xib
    CustomView

如果这是正确的,那么将创建您的CustomView,但因为它不是从CustomView.xib读取的,所以它没有分配任何IBOutlets。

但是,如果您的CustomViewController.xib如下所示

CustomViewController.xib
    CustomView
        UITextField -> linked to IBOutlet textField of CustomView

然后这应该工作。 CustomView实例的IBOutlet应该由CustomViewController.xib设置。

比在CustomViewController.xib中设置任何IBOutlets更好的方法是在您的CustomView中实现awakeAfterUsingCoder:并通过在那里加载CustomView.xib来创建替换对象。这样,您的CustomView仍然是真正的自定义,您不必编辑其他XIB来更改结构,添加/删除IBOutlet等。

答案 2 :(得分:1)

正如Acula博士的回答,这可能是因为自定义视图的nib在从另一个nib(嵌套nib加载)加载时是延迟加载的,所以我们需要手动实例化它。在swift代码中将如下所示:

    override func awakeFromNib() {
    super.awakeFromNib()
        self.customview = UINib(nibName: "CustomViewNib", bundle: nil).instantiateWithOwner(self, options:nil)[0] as!  UIView
        self.customview?.frame = self.viewContainer.bounds
        self.viewContainer.addSubview(self.customview!)
}