我尝试找到一些相关的问题,却无法得到任何东西,希望有人可以提供帮助。
我在故事板上设置了一些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
}
}
我显然遇到错误,因为在创建对象时需要指定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)
}
}
我似乎无法使用i
代替let
来保持var
不可变。
答案 0 :(得分:7)
简化我之前的答案,这很快,并避免了其他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)")
}
}
}
以下是如何使用它将objectID设置为1来推送到导航控制器:
self.navigationController.pushViewController(DetailViewController.instantiate(1), animated: true)
链接到GitHub上的示例: https://github.com/hammadzz/Instantiate-ViewController-From-Storyboard-With-Data
答案 1 :(得分:3)
下面是两个帮助程序,一个是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: ".")
}
}
以下是如何使用视图控制器中的值设置从故事板进行实例化。这是魔术:
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()
}
}
}
(架构影响/复制Kickstarter的开源iOS项目)
答案 2 :(得分:1)
解决此问题的一种(丑陋)方法:
您可以在代码中设置.cell{
display:table-cell;
height:20px;
width:20px;
border:1px solid black;
}
.row{
display:block;
}
来自外部缓冲区(本例中为AppDelegate变量)
let i
当您通过Storyboard启动UIViewController时:
required init?(coder aDecoder: NSCoder) {
self.i = UIApplication.shared().delegate.bufferForI
super.init(coder: aDecoder)
}
修改强> 您不必通过AppDelegate传递值。更好地回答here。