无法以编程方式在Swift中创建UIViewController

6
当我尝试在Swift中创建一个UIViewController实例时,即使我没有在视图控制器中定义任何指定的初始化程序(或其他内容,FWIW),所有继承的初始化程序都不可用。
此外,如果我尝试通过将其设置为根视图控制器来显示它,它永远不会被显示。
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.

        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        window?.makeKeyAndVisible()
        window?.backgroundColor = UIColor.greenColor()



        let vc = ImageViewController()
        window?.rootViewController = vc

        return true
    }

视图控制器的代码只是Xcode的模板:

import UIKit

class ImageViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

有人知道发生了什么吗???

你尝试过实现 required init(coder aDecoder: NSCoder!) 吗? - Dreaming In Binary
我只是这样做了,那么这就是它唯一能识别的初始化。但是,我不需要它。我想要self.init(nibName:nil,bundle:nil)。出于某种原因,即使我没有在UIViewController的子类中添加指定的init,所有继承的初始化程序似乎都已经消失了。 - cfischer
问题在于你正在创建一个空的vc。你是使用storyboards还是nibs? - Lyndsey Scott
我正在使用 nibs,但它看起来不像是 nil: po vc 0x00007fa742b00000 { UIKit.UIViewController = { UIKit.UIResponder = { ObjectiveC.NSObject = {} } } } - cfischer
"Nil" 是错误的词... 我的意思是没有界面的 VC。 - Lyndsey Scott
3个回答

7

正如您所指出的:只要在objective-C中的nib名称与类名匹配,即使在初始化视图控制器时没有指定nib名称,视图控制器仍将查找与视图控制器类名匹配的nib文件

但由于某种原因(可能是bug),Swift中不是这种情况。

而不是写:

let vc = ImageViewController()

在初始化视图控制器时,您必须明确指定一个接口:

let vc = ImageViewController(nibName: "nibName", bundle: nil)

1
好的,现在它有点可行了。 :-) 如果我明确调用nibName:,bundle:初始化器(即使自动完成不会识别它),并传递xib文件的名称,那么它就可以工作了。然而,这并不是期望的行为:如果我只调用init或init(nibName:nil, bundle:nil),它应该通过查看类的名称来获取xib文件的名称。但是它没有。 :-( - cfischer
@cfisher 但是你的初始化在哪里? - Lyndsey Scott
我在视图控制器中没有定义任何初始化。代码完全是Xcode模板提供的那个。它是问题末尾附带的那个。我是从我的ApplicationDelegate中调用它的,在应用程序完成加载时使用options方法。 - cfischer
@cfisher 好的,那就是你的问题了。无论如何,无论是在你的应用程序委托中还是在自定义初始化中,你都必须明确地传递/包含你的xib文件的名称。“它应该通过查看类名来获取xib文件的名称”这种说法是不正确的。即使是苹果也在他们的文档中将上述方法列为“视图控制器类的指定初始化程序”:https://developer.apple.com/library/ios/Documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/instm/UIViewController/initWithNibName:bundle: - Lyndsey Scott
init(nibName nibName: String?, bundle nibBundle: NSBundle?) 是UIViewController的指定初始化程序。但是,除非nib文件的名称与类的名称不同,否则您无需为nib文件指定名称。 - cfischer
显示剩余5条评论

3

为了方便起见,我想到了这个解决办法,这样我就不必在每个地方都使用更长的初始化程序。我有一个BaseViewController,所有我的控制器都扩展自它。

init () {
    let className = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last
    super.init(nibName: className, bundle: NSBundle(forClass: self.dynamicType))
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

注意,使用 NSBundle(forClass: self.dynamicType) 可以处理不同目标中的命名空间。

然后当我想要实例化一个 ViewController 时,我使用 MyViewController(),就像在Objective-C中一样。


0
let Vc = UIViewController()
vc.view = yourview

或将上述视图控制器添加为子视图控制器

configureChildViewController(vc,onView:yourview in Viewcontroller)

使用此扩展来操作 UiViewController

extension UIViewController {


func configureChildViewController(childController: UIViewController, onView: UIView?) {
    var holderView = self.view
    if let onView = onView {
        holderView = onView
    }
    addChildViewController(childController)
    holderView.addSubview(childController.view)
    constrainViewEqual(holderView, view: childController.view)
    childController.didMoveToParentViewController(self)
}

func scatterChildViewController(childController: UIViewController) {
    childController.willMoveToParentViewController(self)
    childController.view.removeFromSuperview()
    childController.removeFromParentViewController()
}

func constrainViewEqual(holderView: UIView, view: UIView) {
    view.translatesAutoresizingMaskIntoConstraints = false
    //pin 100 points from the top of the super
    let pinTop = NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal,
        toItem: holderView, attribute: .Top, multiplier: 1.0, constant: 0)
    let pinBottom = NSLayoutConstraint(item: view, attribute: .Bottom, relatedBy: .Equal,
        toItem: holderView, attribute: .Bottom, multiplier: 1.0, constant: 0)
    let pinLeft = NSLayoutConstraint(item: view, attribute: .Left, relatedBy: .Equal,
        toItem: holderView, attribute: .Left, multiplier: 1.0, constant: 0)
    let pinRight = NSLayoutConstraint(item: view, attribute: .Right, relatedBy: .Equal,
        toItem: holderView, attribute: .Right, multiplier: 1.0, constant: 0)

    holderView.addConstraints([pinTop, pinBottom, pinLeft, pinRight])
}

}


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