【问题标题】:Where to initialize custom UIView, instantiated in Interface Builder?在哪里初始化自定义 UIView,在 Interface Builder 中实例化?
【发布时间】:2011-06-02 12:50:52
【问题描述】:

我有一个在 XIB 文件中实例化的 UIView 子类。我需要它来做一些初始化(设置一些变量并创建一个子视图)。

但是,我并不总是通过 Interface Builder 实例化此视图。我也以编程方式进行。在这两种情况下,初始化需要相同。

我指定的初始化器是initWithValues:

问题是; 在哪里进行初始化?

由于我必须在 2 个不同的位置执行它,我想我需要在一个单独的 initialize 方法(或类似的方法)中重构它,并从 initWithValues: 调用它。

但是当从 IB 加载时,initWithCoder:awakeFromNib 都会被调用。我必须通过哪种方法调用initialize?还是我必须从initWithCoder: 调用initWithValues: 而在awakeFromNib 中什么也不做?

【问题讨论】:

    标签: iphone objective-c cocoa-touch uikit


    【解决方案1】:

    您应该在初始化视图时使用initWithFrame:(因为它是指定的初始化程序)。因此,如果您有 initWithValues:,请确保您从中调用 initWithFrame:

    这样的东西应该适用于初始化:;)

    - (void)initialize{
         //init your ivars here
    }
    
    - (id)initWithCoder:(NSCoder *)aCoder{
        if(self = [super initWithCoder:aCoder]){
            [self initialize];
        }
        return self;
    }
    
    - (id)initWithFrame:(CGRect)rect{
        if(self = [super initWithFrame:rect]){
            [self initialize];
        }
        return self;
    }
    

    我打算添加进一步的解释,但 mplappert 的回答已经足够清楚了。如有必要,请使用awakeFromNib

    【讨论】:

    • 调用超类的两个不同初始化器不是“错误”吗?我不应该从initWithCoder: 调用我的子类的指定初始化程序(initWithValues:)吗?
    • 调用超类的两个不同初始化器不是“错误”吗? →否,因为只会调用其中一个。我不应该从 initWithCoder: 调用我的子类的指定初始化程序 (initWithValues:) 吗? →部分是的。 initWithCoder:希望您取消归档对象。这就是为什么我们称之为 [super initWithCoder];通过这样做,视图将被初始化。现在您只需要初始化其他 ivars,我假设您正在初始化方法中执行此操作。
    【解决方案2】:

    不幸的是,上述答案没有考虑到这些事情: - (void) awakeAfterUsingCoder - 以及在编码器创建任何内容之后调用它的事实(每个 Xib 视图一次)。 awakeFromNib 也有同样的命运,我注意到了。 (我发现这个的原因)

    另一个初始化问题是自定义视图可以避免使用 initWithCoder 和 initWithFrame。如果它们被调用,延迟加载(尽管对视图本身并不重要)意味着您“可能”能够修改值。我相信我已经在 initWithCoder 中这样做了,但是如果你随后在 awakeFromNib 中初始化值,它至少会被撤消一次。

    我已经做到了:

    - (void) awakeFromNib (or didMoveToSuperView);
    {
        BOOL called = NO;
        if(!called)
        {
        called = YES;
        }
    
    }
    

    我使用的另一种方法是简单地调用所需的初始化程序,然后调用我自己的类或特定于超类的初始化程序。

    我也在寻找一个我可以依赖的可靠的一次性地方。在那之前,我希望我的头痛可以为下一个人节省一个小时左右。

    史蒂夫

    【讨论】:

    • 我认为didMoveToSuperView 对于大多数视图来说是一个非常好的地方——它将涵盖手动和 NIB 实例化,而无需多个 init 方法。如果您需要视图在屏幕上显示之前执行任何逻辑,那不是很好,但如果您这样做,那么可能有问题......
    • 是的,这实际上是我最终使用的方法,但即使它也有缺陷。当它被删除并且它的 superview 为 nil 时,它也会被调用。不利于重新排列,所以我添加了一个“if superview nil”测试,就像被调用的测试一样。小心那个!感谢您的回答:D
    【解决方案3】:

    这取决于您需要初始化什么。只要awakeFromNib 被调用,您的视图的所有出口和操作连接就会建立,而initWithCoder: 的情况并非如此。因此,如果您需要依赖这些连接,请使用 awakeFromNib。否则,您可以安全地在 initWithCoder: 中进行所有初始化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多