【问题标题】:Which initializer(s) to override for UITableViewController subclass为 UITableViewController 子类覆盖哪个初始化程序
【发布时间】:2009-04-13 04:04:16
【问题描述】:

我有一个被实例化的UITableViewController 子类,具体取决于它的使用位置、NIB 或通过代码。在这两种情况下,我都想在初始化方法中进行自定义。这是否意味着我需要同时实现initWithNibName:bundle: initWithCoder:,并且每个方法都会调用其各自的超级初始化程序?

虽然我现在不需要这个,但如果我也希望能够使用initWithStyle: 实例化视图控制器怎么办?那么我是否需要 3 种不同的 init 方法来复制相同的行为?

这似乎违反了整个指定的初始化器约定,因为本质上会有 3 个单独的初始化器,它们最终不会调用一个通用的 init 方法。或者有没有办法在支持 3 种不同的实例化路由的同时创建一个通用的指定初始化器?

【问题讨论】:

    标签: iphone objective-c cocoa-touch designated-initializer


    【解决方案1】:

    我的困惑是基于一个错误的信念,即每个类都应该有一个指定的初始值设定项。这不是真的,在 UITableViewController 的情况下,有 3 个指定的初始值设定项(据我所知):

    1. initWithStyle: 本地声明
    2. initWithNibName:bundle: 继承自 UIViewController
    3. initWithCoder: 来自采用NSCoding 协议

    您需要在子类中覆盖其中的 1 个或更多,具体取决于子类的实例化方式。就我而言,我必须实现#2 和#3,因为该类可以从 NIB 加载,或者通过参考 NIB 的代码实例化。 (我想你很少会在一个类中同时使用 initWithStyle:initWithNibName:bundle:。)

    我发现 Apple 的 Coding Guidelines for Cocoa 很有帮助。

    【讨论】:

    • 这不准确。 -[UIViewController initWithCoder:] 似乎调用了 -[UIViewController initWithNibName:bundle:]。无需覆盖它。听从 KennyTM 的建议。
    • 它是准确的。我有一种情况,只有 initWithCoder 被调用。 (我已经覆盖了所有 3 种方法)。
    • 在 iOS8 上真正令人困惑的是 initWithStyle: 调用 initWithNibName:bundle: 并且两者都必须声明为指定的初始化程序。这不符合快速初始化规则。在 iOS8 上,如果你没有定义 initWithNibName:bundle: 并调用 initWithStyle:,应用程序会崩溃。这已在 iOS9 上修复。
    【解决方案2】:

    在内部,

    • UITableViewController 的-initWithStyle: 调用super 的-init 然后设置_tableViewStyle ivar。
    • UIViewController 的-init 只需使用默认参数调用-initWithNibName:bundle:
    • UITableViewController 覆盖-initWithNibName:bundle:

    因此,如果您覆盖 -initWithNibName:bundle:,那么 -initWithStyle: 也将采用更改。当然,为了安全起见(因为您不应该依赖实现细节),请同时覆盖它们。

    (并且无需覆盖 -initWithCoder:,除非您取消/归档实例。)

    【讨论】:

    • 覆盖 -initWithNibName:bundle: 本身应该是安全的,因为它不是真正的实现细节,而是框架的一个方面,指定的初始化器在继承链的整个过程中被调用。而继承链本身就是 UITableViewController 接口的一部分。
    【解决方案3】:

    澄清一下,initWithStyle:UITableViewController 在文档中唯一发布的初始化程序,是其一个明确指定的初始化程序。

    initWithNibName:bundle: 继承自 UIViewController 并且是该类的指定初始化程序。因此,根据 Cocoa 指南,UITableViewController 必须 覆盖此方法(通过实现它)。但是,这并不能使它成为UITableViewController 的指定初始化器。

    initWithCoder: 正如您所指出的,是来自NSCoding 的隐式指定初始化程序。

    【讨论】:

      【解决方案4】:

      实施:

      - (void) viewDidLoad
      

      并在那里进行组件初始化。

      它的优点是只有在实际请求视图时才进行初始化。

      或者只是创建一个由所有初始化程序调用的单独设置方法。

      【讨论】:

      • 我不能使用 viewDidLoad 因为,具体来说,我需要设置 self.navigationItem 可以在加载视图之前使用。我可以制作一个单独的设置方法。那么 NSCoding 从根本上说是“单一指定初始化器”规则的一个例外吗?
      【解决方案5】:

      对以上帖子的补充,该参考-initWithCoder:

      如果您通过界面构建​​器添加了视图控制器到其父级(例如:如果视图控制器连接到界面构建器中的选项卡栏控制器),那么您需要覆盖–initWithCoder。

      (-initWithNibName 只会在您以编程方式创建视图控制器时被调用。)

      【讨论】:

        猜你喜欢
        • 2018-10-25
        • 1970-01-01
        • 1970-01-01
        • 2012-10-22
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多