故事板中的UIViewController自定义初始化

raf*_*lio 18 uiviewcontroller ios swift

我试着找到一些相关的问题,却无法得到任何东西,希望有人可以提供帮助.

我在故事板上设置了一些UIViewController.然后我想在代码中加载一个视图控制器并将其推送到导航堆栈.我想出正确的方法是使用

instantiateViewControllerWithIdentifier

这个调用init(coder: NSCoder),一切都很好,我的程序工作,但我希望能够有一个自定义初始化程序,为我的视图控制器设置一些变量.考虑以下:

class A : UIViewController {   

  let i : Int

  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    // property self.i not initialized at super.init call   
  }

}
Run Code Online (Sandbox Code Playgroud)

我显然得到一个错误,因为i需要在创建对象时指定.对此有何解决方案?我对以后声明和配置它并不感兴趣,i因为var它失败了,我不再拥有i不可变的编译器保证.

澄清编辑

假设我有一个当前加载的ViewController变量i.该值是可变的并且可以改变.现在假设从这个ViewController我想呈现另一个,并用它初始化它i.

class ViewController: UIViewController {

   var i : Int

   // ... other things

  // in response to some button tap...
  @IBAction func tappedButton(sender: AnyObject) {
    let st = UIStoryboard(name: "Main", bundle: nil)
    let vc = st.instantiateViewControllerWithIdentifier("AControllerID") as! A
    // How do I initialize A with i ?
    self.presentViewController(vc, animated: true, completion: nil)
  }

}
Run Code Online (Sandbox Code Playgroud)

我似乎无法做到这一点,并i通过使用let而不是保持不变var.

hah*_*med 10

简化我之前的答案,这是快速的,并避免了其他hacky修复:

这是一个详细视图控制器,您可能希望从设置了objectID的storyboard实例化:

import UIKit

class DetailViewController: UIViewController {

    var objectID : Int!

    internal static func instantiate(with objectID: Int) -> DetailViewController {

        let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DetailViewController") as DetailViewController
        vc.objectID = objectID
        return vc
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if((objectID) != nil){
            print("Here is my objectID: \(objectID)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是如何使用它来推送一个objectID设置为1的导航控制器:

self.navigationController.pushViewController(DetailViewController.instantiate(1), animated: true)
Run Code Online (Sandbox Code Playgroud)

添加了博客文章: https ://theswiftcook.wordpress.com/2017/02/17/how-to-initialize-a-storyboard-viewcontroller-with-data-without-segues-swift-3-0git/

链接到GitHub上的示例: https ://github.com/hammadzz/Instantiate-ViewController-From-Storyboard-With


hah*_*med 5

下面有两个助手,一个是 Storyboard 枚举,将项目中的每个 Storyboard 作为一个案例添加到该枚举下。该名称必须与 {storyboard_name}.storyboard 文件匹配。故事板中的每个视图控制器都应该将其故事板标识符设置为类的名称。这是非常标准的做法。

import UIKit

public enum Storyboard: String {
    case Main
    case AnotherStoryboard
    //case {storyboard_name}

    public func instantiate<VC: UIViewController>(_ viewController: VC.Type) -> VC {
        guard
            let vc = UIStoryboard(name: self.rawValue, bundle: nil)
                .instantiateViewController(withIdentifier: VC.storyboardIdentifier) as? VC
            else { fatalError("Couldn't instantiate \(VC.storyboardIdentifier) from \(self.rawValue)") }

        return vc
    }

    public func instantiateInitialVC() -> UIViewController {

        guard let vc = UIStoryboard(name: self.rawValue, bundle: nil).instantiateInitialViewController() else {
            fatalError("Couldn't instantiate initial viewcontroller from \(self.rawValue)")
        }

        return vc
    }
}

extension UIViewController {
    public static var defaultNib: String {
        return self.description().components(separatedBy: ".").dropFirst().joined(separator: ".")
    }

    public static var storyboardIdentifier: String {
        return self.description().components(separatedBy: ".").dropFirst().joined(separator: ".")
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是如何使用视图控制器中设置的值从情节提要进行实例化。这就是魔法:

import UIKit

class DetailViewController: UIViewController {

    var objectID : Int!
    var objectDetails: ObjectDetails = ObjectDetails()        

    internal static func instantiate(with objectID: Int) -> DetailViewController {

        let vc = Storyboard.Main.instantiate(DetailViewController.self)
        vc.objectID = objectID
        return vc
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if((objectID) != nil){
            // In this method I use to make a web request to pull details from an API
            loadObjectDetails()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(架构影响/复制 Kickstarter 的开源 iOS 项目)


Tul*_*leb 0

解决这个问题的(丑陋的)方法:

let i您可以在代码中从外部缓冲区设置(本例中为 AppDelegate 变量)

required init?(coder aDecoder: NSCoder) {
    self.i = UIApplication.shared().delegate.bufferForI

    super.init(coder: aDecoder)
}
Run Code Online (Sandbox Code Playgroud)

当您通过 Storyboard 启动 UIViewController 时:

UIApplication.shared().delegate.bufferForI = myIValue
self.navigationController!.pushViewControllerFading(self.storyboard!.instantiateViewController(withIdentifier: "myViewControllerID") as UIViewController)
Run Code Online (Sandbox Code Playgroud)

编辑: 您不必通过 AppDelegate 传递值。最好在这里回答。