好的,StackOverflow上有几十篇关于这个问题的帖子,但没有一个是特别清楚的解决方案.我想创建一个带有随附的xib文件的自定义UIView.要求是:

  • 没有单独的UIViewController-一个完全独立的类
  • 类中的插座,允许我设置/获取视图的属性

我目前的做法是:

  1. 覆盖-(id)initWithFrame:

    -(id)initWithFrame:(CGRect)frame {
        self = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class])
                                              owner:self
                                            options:nil] objectAtIndex:0];
        self.frame = frame;
        return self;
    }
    
  2. 在我的视图控制器中使用-(id)initWithFrame:以编程方式实例化

    MyCustomView *myCustomView = [[MyCustomView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
    [self.view insertSubview:myCustomView atIndex:0];
    

这很好(尽管从不调用[super init],只是使用加载的nib的内容设置对象似乎有点可疑——这里有建议add a subview in this case也很好).然而,我也希望能够从故事板实例化视图.所以我可以:

  1. 在情节提要中的父视图上放置UIView
  2. 将其自定义类设置为MyCustomView
  3. Override -(id)initWithCoder:–我见过的代码通常符合以下模式:

    -(id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            [self initializeSubviews];
        }
        return self;
    }
    
    -(id)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self initializeSubviews];
        }
        return self;
    }
    
    -(void)initializeSubviews {
        typeof(view) view = [[[NSBundle mainBundle]
                             loadNibNamed:NSStringFromClass([self class])
                                    owner:self
                                  options:nil] objectAtIndex:0];
        [self addSubview:view];
    }
    

当然,这不起作用,因为无论我使用上述方法,还是以编程方式实例化,都会在输入-(void)initializeSubviews并从文件加载nib时递归调用-(id)initWithCoder:.

其他几个SO问题也涉及到这一点,例如herehereherehere.然而,没有一个答案能令人满意地解决问题:

  • 一种常见的建议似乎是将整个类嵌入到UIViewController中,然后在那里进行nib加载,但对我来说,这似乎不太理想,因为它只需要添加另一个文件作为包装器

有没有人能给出解决这个问题的建议,让工作插座在定制的UIView中以最小的小题大做/没有薄的控制器包装?或者,有没有一种替代的、更干净的方式来用最少的样板代码来做事情?

推荐答案

你的问题是从(initWithCoder:的后代)拨打loadNibNamed:.loadNibNamed:个内部呼叫initWithCoder:.如果您想覆盖故事板编码器,并始终加载xib实现,我建议使用以下技术.将属性添加到视图类中,并在xib文件中将其设置为预定值(在用户定义的运行时属性中).现在,在拨打[super initWithCoder:aDecoder];之后,判断属性的值.如果是预定值,不要拨打[self initializeSubviews];.

比如说:

-(instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];

    if (self && self._xibProperty != 666)
    {
        //We are in the storyboard code path. Initialize from the xib.
        self = [self initializeSubviews];

        //Here, you can load properties that you wish to expose to the user to set in a storyboard; e.g.:
        //self.backgroundColor = [aDecoder decodeObjectOfClass:[UIColor class] forKey:@"backgroundColor"];
    }

    return self;
}

-(instancetype)initializeSubviews {
    id view =   [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil] firstObject];

    return view;
}

Ios相关问答推荐

React Native Text组件内部TextInput组件在iOS上的问题:在TextInput组件内部键入文本时失go 焦点

实例方法wait在异步上下文中不可用;请改用TaskGroup;这是Swift 6中的错误''

创建带有Flutter 翼的会所头像

如何通过S定义的对象设置删除基于块的观察者的测试?

如何使用超薄material ,但没有浅色/填充?

如何在后台显示 Swift UI 中的通讯通知?

为什么IOS多行文本输入在React原生纸张对话框中无法正常工作?

如何在用户点击的位置使用SceneKit渲染球体?

不使用故事板创建 iMessage 应用程序

更新 flutter 和 xcode 后 Xcode 14.3 中缺少文件 (libarclite_iphoneos.a)

如何在 Mac OS Ventura 中使用 Xcode 13

如何在 SwiftUI 中将选项卡放在滚动视图中?

Xcode 14 弃用了位码 - 但为什么呢?

如何在 UIActivityViewController 中设置邮件主题?

当键盘出现在 iOS 中时,将 UIView 上移

判断可选数组是否为空

~= Swift 中的运算符

应用程序不包含正确的测试版权利

在 React Native 中保存敏感数据

如何立即移动 CALayer(无动画)