Custom init of UIViewController from storyboard

后端 未结 3 1104
被撕碎了的回忆
被撕碎了的回忆 2020-12-29 05:52

I tried finding some relevant questions but couldn\'t get anything, hope someone can help.

I set up some UIViewController\'s on a storyboard. I then want to load one

相关标签:
3条回答
  • 2020-12-29 06:01

    A simplification of my prior answer which is quick and avoids alternative hacky fixes:

    Here is a detail view controller you may want to instantiate from storyboard with an objectID set:

    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)")
            }
        }
    }
    

    Here is how you would use it to push onto a navigation controller with objectID set to 1:

    self.navigationController.pushViewController(DetailViewController.instantiate(1), animated: true)
    

    Added a blog post: https://theswiftcook.wordpress.com/2017/02/17/how-to-initialize-a-storyboard-viewcontroller-with-data-without-segues-swift-3-0git/

    Link to example on GitHub: https://github.com/hammadzz/Instantiate-ViewController-From-Storyboard-With-Data

    0 讨论(0)
  • 2020-12-29 06:01

    Below are two helpers, one is a Storyboard enum, add each and every storyboard in your project as a case under this enum. The name must match the {storyboard_name}.storyboard file. Each view controller in your storyboard should have its storyboard identifier set to the name of the class. This is pretty standard practice.

    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: ".")
        }
    }
    

    Here is how you can instantiate from storyboard with a value set in your view controller. Here is the magic:

    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()
            }
        }
    }
    

    (Architecture influenced/copies Kickstarter's open source iOS project)

    0 讨论(0)
  • 2020-12-29 06:07

    An (ugly) way to solve this issue:

    You can set your let i from an external buffer in your code (AppDelegate variable in this example)

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

    And when you initiate your UIViewController through Storyboard:

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

    EDIT: You don't have to pass the value through the AppDelegate. Better answer here.

    0 讨论(0)
提交回复
热议问题