为什么在Swift中无法调用UIViewController的默认super.init()函数?

110

我不使用从storyboard加载的UIViewController,我想要一个自定义的init函数,在其中可以传递某个对象的NSManagedObjectID。我只想像在Objective-C中一样调用super.init()。就像这样:

init(objectId: NSManagedObjectID) {
    super.init()
}

但是我得到了以下编译器错误:

必须调用父类UIViewController的指定初始化方法

我现在还能不能这样做呢?

4个回答

140

4
目前我无法在一个不是从nib文件加载的UIViewController子类中创建自定义的init方法,对吗? - SirRupertIII
1
啊,谢谢!我传递了空字符串作为nib名称。 - SirRupertIII
仅重写 initWithNibName:bundle: 是不够的;编译器会抛出错误并建议您还实现(必需的)initWithCoder:。我猜两者都是指定初始化程序?但只有 withCoder 在 Swift 中被标记为“required”... - Nicolas Miari
2
哦,经过一番搜索,原来 initWithCoder: 是来自于 NSCoding 协议... 我仍然无法确定它在初始化 UIViewController 实例中的作用,无论是 UIViewController 还是其任何超类的 "指定" 初始化程序... - Nicolas Miari
8
感谢!在设置好你的let属性后,只需调用以下代码即可进行快速复制/粘贴: super.init(nibName: nil, bundle: nil) - Ferran Maylinch
3
Init With Coder被用于需要进行状态恢复的情况。当你使用状态恢复功能保存视图控制器的状态时,编码器将返回在状态被保存时所保存的值。从那里,你可以重建视图控制器到上次关闭应用程序时的最初状态。因此,对于用户来说,这就是他们离开应用程序时的状态。 - Esko918

50

另一个不错的解决方案是将您的新初始化程序声明为 convenience 初始化程序,如下所示:

convenience init( objectId : NSManagedObjectID ) {
    self.init()

    // ... store or user your objectId
}
如果在子类中完全没有声明指定的初始化程序,它们会自动继承,并且您可以在方便的初始化程序中使用self.init()
对于UIViewController,默认的init方法将调用init(nibName nibNameOrNil: String!,bundle nibBundleOrNil: NSBundle!),并为两个参数都使用nil(在UIViewController上单击命令按钮可以获得该信息)。
TL;TR:如果您喜欢以编程方式使用UIViewController,这是一个完整的工作示例,它添加了一个具有自定义参数的新初始化程序。
class MyCustomViewController: UIViewController {
    var myString: String = ""

    convenience init( myString: String ) {
        self.init()

        self.myString = myString
    }
}

这是一种更优雅的解决方案,适用于任何通用情况。 - Ciprian
2
我尝试在一个扩展中进行此操作,结果出现递归调用。 - Danyal Aytekin
19
这个答案的"诀窍"在于myString被设置为"",所以不需要init。如果您不想使用初始值,这个解决方案就不奏效了,在这种情况下,您需要使用self.init(nibName: nil, bundle:nil) - Dan Rosenstark
2
@Yar 或者可以将 myString 属性设为可选。 - Klaas
1
@Klaas 是的:我的问题是我只是使用初始化器来避免可选项并使我的代码编译。 - Dan Rosenstark
显示剩余2条评论

34

为了改进occulus的回答:

init() {
     super.init(nibName: nil, bundle: nil)
}

18
更新:添加链接

https://developer.apple.com/documentation/uikit/uiviewcontroller/1621359-init

根据iOS文档,UIViewController的指定初始化器是initWithNibName: bundle:
如果你要子类化UIViewController,即使你不使用NIB,也必须调用此方法的super实现。
你可以按照以下方式完成:
init(objectId : NSManagedObjectID) {

    super.init(nibName: (xib's name or nil'), bundle: nil)

   // other code...
}

或者

将一个新的初始化方法声明为便利初始化方法:

 convenience init( objectId : NSManagedObjectID ) {

    self.init()

     // other code...

}


1
你应该链接到原始网页进行归属,而不是留下截图。 - Nathan Tuggy
我使用了和@NcNc说的一样的过程。这对我有用。这是链接:link - Anil Gupta
@NathanTuggy 不,他不应该这样做。链接有一个过期或移动的功能。谁想看到404错误而不是他/她正在寻找的信息呢? - mykolaj
2
@mykolaj:信息已经在这个答案中了。(否则我会要求删除这个仅包含链接的答案。)但是归属也很重要,这样任何人都可以找到它来给予他们信用。截图无法达到这个效果,但链接可以。如果一个链接失效了,那么这可能不太好,但你绝对不能告诉我这种情况比根本没有得到任何形式的归属更糟糕。SO 对仅包含链接的答案产生反感,而不是对链接本身。链接和信息合在一起才是理想的解决办法。 - Nathan Tuggy
@NathanTuggy 我刚刚添加了链接。谢谢你的提醒。 - NcNc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接