在ios 8 beta 5中,视图控制器的nib文件被破坏了吗?
我在ios 8 beta 4中创build了一个testing项目,作为主视图控制器和第二个视图控制器,创build为具有xib文件的UIViewController子类。
我在主控制器上放了一个button来显示第二个控制器:
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } @IBAction func testVCBtnTapped() { let vc = TestVC() presentViewController(vc, animated: true, completion: nil) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. }
}
我运行应用程序,然后按下button呈现第二个控制器 – 一切都很好
移动到Xcodetesting版5,我运行该应用程序,当我按下button的屏幕变黑。
因为我知道他们与init代码搞混了,所以我尝试了覆盖,看看它会修复它:
class TestVC: UIViewController { override init() { super.init() } required init(coder aDecoder: NSCoder!) { super.init(coder: aDecoder) } override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. }
同样的问题。 将所需要的和覆盖改为xcode所接受的所有可能的组合都不起作用。
如果我使用故事板来创build另一个控制器,并继续这一切都很好。
有任何想法吗?
编辑 – 新的信息
- 在初始化尝试nibName =零 – 同样的问题
- 在目标c中创build相同的应用程序,它工作正常
显然是一个迅速的testing版5问题
我不知道这是否是一个错误,但这绝对是一个变化。 当然,他们可能会改变它…无论如何,种子5的规则是:
视图控制器不会因为它具有相同的名称而自动find.xib。 您必须明确提供名称。
所以,在你的情况下,初始化这个视图控制器的任何尝试必须最终调用nibName:bundle:
显式nib名称( "TestVC"
),我假设。
如果你想通过调用来初始化
let vc = TestVC()
正如你在呈现视图控制器中所做的那样,只需在显示的视图控制器中重写init()
以调用super.init(nibName:"TestVC", bundle:nil)
,这就是你所需要的(除了我认为你也会需要在这里讨论的init(coder:)
塞子)。
编辑你是绝对正确的,这是一个快速的问题。 发现得好。 在Objective-C中,使用init
(或new
)进行init
仍然正常; 视图控制器正确地find它的同名.xib文件。
另一个编辑决定因素不是Objective-C或Swift是否调用init
。 视图控制器本身是用Objective-C还是用Swift编写的。
最终编辑解决方法是声明你的Swift视图控制器是这样的:
@objc(ViewController) ViewController : UIViewController { // ...
圆括号中的名字除掉了引起问题的名字。 很可能在下一个版本中,这个问题将被修复,您可以再次使用@objc
。
另一个最后的编辑坏消息:我提交的这个错误报告回来了“按预期工作”。 他们指出,我所要做的就是在周围的模块之后命名.xib文件,例如,如果我的应用程序叫做NibFinder ,那么如果我命名我的.xib文件NibFinder.ViewController.xib ,它会在实例化ViewController()
时自动findViewController()
。
这是真的,但在我看来,它只是重述错误; Swift查找过程正在预先考虑模块名称。 所以苹果公司说,我应该指责下,并预先给我的.xib文件相同的模块名称,而我说的是,苹果应该closures下去,并取消模块名称,因为它执行search。
编辑,这是真正的真正的最终这个错误是固定的iOS 9testing版4,所有这些解决方法变得不必要。
如果你需要iOS8的支持。 你可以在UIViewController上使用扩展
extension UIViewController { static func instanceWithDefaultNib() -> Self { let className = NSStringFromClass(self as! AnyClass).componentsSeparatedByString(".").last let bundle = NSBundle(forClass: self as! AnyClass) return self.init(nibName: className, bundle: bundle) } }
然后用这种方法创build实例
let vc = TestVC.instanceWithDefaultNib()
这个把戏适合我。 如果您有基本视图控制器类,则可以覆盖返回类名(等于xib文件名)的nibName属性。
class BaseViewController: UIViewController { override var nibName: String? { get { guard #available(iOS 9, *) else { let nib = String(self.classForCoder) return nib } return super.nibName } } }
从这个基类inheritance的所有视图控制器都可以加载它们的xib。 例如MyViewController:BaseViewController可以加载MyViewController.xib
这里的代码,基于弗朗西斯科的答案。 它包含检查nib文件是否退出,所以当你加载没有关联xib的UIViewController时,应用程序不会崩溃(你可以在iOS8上重现它)
override var nibName: String? { get { let classString = String(describing: type(of: self)) guard nibBundle?.path(forResource: classString, ofType: "nib") != nil else { return nil } return classString } } override var nibBundle: Bundle? { get { return Bundle.main } }
Swift3:
extension UIViewController { static func instanceWithDefaultNib() -> Self { let className = NSStringFromClass(self).components(separatedBy: ".").last return self.init(nibName: className, bundle: nil) } }