How to initialize ViewController from storyboard using it's Coder - ios

I realize that this might be difficult to achieve, but I would like to be able to initialize ViewControllers from storyboard using init(coder: NSCoder) function directly. I mean not using storyboard.instantiateViewController(identifier: coder: ) - I know I could use this, but this is what I would like to skip. Instead I would prefer to have a init in ViewController like this:
init(viewModel: ViewModel) and use this init to initialize this ViewController from the storyboard. Inside this init I imagine having some mechanism that would open my storyboard, and extracted it's coder somehow, so that I could write:
static let storyboard = UIStoryboard(named: "Game")
private let viewModel: ViewModel
init(viewModel: ViewModel) {
self.viewModel = viewModel
let identifier = String(describing: Self.self)
let coder: NSCoder = Self.storyboard.somehowGetTheCoderForViewController(withId: identifier)
super.init(coder: coder)
}
Problem is how to read storyboard in such a way that I was able to get the coder of particular ViewController from it.
Again - I know this can be solved by using something like this
storyboard.instantiateViewController(identifier: String(describing: Self.self)) { coder in
Self.init(coder: coder, viewModel: viewModel)
}
But Im looking for a way to not use instantiateViewController, and just be able to get the coder, so that later I could just initiate VC like this:
let viewController = ViewContorller(viewModel: viewModel)
So the question is how to unpack storyboard, and retrieve coder object for some ViewController.

You are not supposed to do this.
As the documentation of init(nibName:bundle:) says:
This is the designated initializer for this class. When using a storyboard to define your view controller and its associated views, you never initialize your view controller class directly. Instead, view controllers are instantiated by the storyboard either automatically when a segue is triggered or programmatically when your app calls the instantiateViewController(withIdentifier:) method of a storyboard object.
When initialising a VC using an initialiser, that initialiser is what you should use, not init(coder:). If you use storyboards, then you should use instantiateViewController, or use segues to get new VCs.
So to achieve this syntax:
let viewController = ViewContorller(viewModel: viewModel)
You can put your VCs in xib files, and do:
init(viewModel: ViewModel) {
self.viewModel = viewModel
let identifier = String(describing: Self.self)
let coder: NSCoder = Self.storyboard.somehowGetTheCoderForViewController(withId: identifier)
super.init(nibName: String(describing: Self.self), bundle: nil)
}
If you must use storyboards, then you can't use an initialiser syntax for initialising VCs. You can instead make a factory method, such as:
let viewController = ViewContorller.from(viewModel: viewModel)
And implement it using UIStoryboard.instantiateViewController.

This is why the initializer instantiateViewController(identifier:creator:) exists.
https://developer.apple.com/documentation/uikit/uistoryboard/3213989-instantiateviewcontroller
You receive the coder and use it to call a custom initializer that itself calls the coder initializer but also does other custom initialization.
To illustrate, suppose we have a ViewController class with a message String property to be presented to the user in a UILabel when the view appears. So we've given ViewController an init(coder:message:) initializer:
class ViewController: UIViewController {
#IBOutlet var lab : UILabel!
var message: String = ""
convenience init(coder:NSCoder, message:String) {
self.init(coder:coder)!
self.message = message
}
override func viewDidLoad() {
super.viewDidLoad()
self.lab.text = self.message
}
}
Left to its own devices, however, the runtime will never call our init(coder:message:) initializer; it knows nothing of it! The only way the runtime knows to instantiate a view controller from a storyboard is by calling init(coder:). But we can call init(coder:message:) when we instantiate the view controller from the storyboard.
Suppose this is the storyboard's initial view controller, and we're calling it in the scene delegate at launch time:
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
guard let scene = (scene as? UIWindowScene) else { return }
let message = "Howdy, world!" // or whatever
self.window = UIWindow(windowScene: scene)
let sb = UIStoryboard(name: "Main", bundle: nil)
self.window?.rootViewController = sb.instantiateInitialViewController {
return ViewController(coder: $0, message: message)
}
self.window?.makeKeyAndVisible()
}
We call instantiateViewController(identifier:creator:) and the creator: function calls init(coder:message:) — which, in turn, calls init(coder:). Thus our use of the creator: function is legal, and the view appears correctly.

Related

get Nil when calling for IBOutlet properties in function

i’m working in swift and i’m trying to use the .frames to check if 2 objects of type CGRect intersect.
i have my View Controller Class and a CircleClass, the CircleClass creates a circle that has gesture recognition so i can drag the circles that i create where i want to, now i want to add the option that if at the end of the drag the subview intersects my trashimageView (image view that will always be in the low-right corner of the view for all devices it's like a trashcan) it can delete the circle or subView.
the problem is that when i try to call trashImageView.frame in a function “deleteSubView” that i’ve created in the View Controller i get nil and my app crashes.
But if the IBOutlet is in the VC and my function is defined in my VC, also i can call the trashImageView.frame (CGRect Value) in the viewDidLoad and there is fine, but not in my function, why do i get nil for this value??
class ViewController: UIViewController {
#IBOutlet var trashImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
//here i can print the CGRect value just fine
print("my imageView init: \(trashImageView.frame)")
}
func deleteSubView(subView: UIView){
// Here i get nil from the trashImageView.frame
if (subView.frame.intersects(trashImageView.frame)) {
print("intersection")
subView.removeFromSuperview()
}
}
}
i've checked that the Nil value is from the 'trashImageView.frame' and that the connection with the storyboard is good.
i call the function ‘delete subView’ from another class but should that matter? i don’t understand what is the error here, why do i get nil? help please.
Since your UIViewController is declared and instantiated using storyboard my guess is that you are creating the view controller using it's no arg initializer, i.e.: let controller = MyController() if you must create an instance of the controller programmatically do so by obtaining a reference to the Storyboard that contains the controller, i.e like this:
NOTE: Here I'm using "MyController" as the name of the class and the identifier that has been set in the storyboard.
func createMyController() -> MyController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "MyController")
return controller as! MyController
}
I'd also add a guard for view load state in your deleteSubview(:subView) method, so something like this:
func deleteSubView(subView: UIView) {
guard isViewLoaded else { return }
// Here i get nil from the trashImageView.frame
if (subView.frame.intersects(trashImageView.frame)) {
print("intersection")
subView.removeFromSuperview()
}
}

Create a UIViewController concrete class from its type

I wish to create a concrete class from UIViewController type, something like this
func create(with type : UIViewController.Type)->UIViewController{
return type.init(coder: NSCoder())!
}
Apparently, UIViewController's designated initializer is only init(coder : NSCoder). And, when I try to pass in NSCoder() (as shown in the above case), the app crashes.
Anyone knows a better solution in creating a UIViewController concrete class from its type? Or am I pass in the wrong NSCoder in this case?
Code completion does not show this option, but this compiles and runs without a problem:
func create(with type : UIViewController.Type) -> UIViewController {
return type.init()
}
If you just want to create the view controller programmatically or from a XIB then just use the base constructor.
let viewController = MyViewController()
If you have a XIB with the same file name as the class then it will load it automatically.
If you want to load it from a storyboard then you need to define an identifier for the view controller in the storyboard and then call:
let storyboard = UIStoryboard(name: "storyboardName", bundle: nil)
storyboard.instantiateViewController(withIdentifier: "myViewControllerIdentifier")
EDIT
If you want a special create function, you can actually create an extension for UIViewController like this:
extension UIViewController {
static func create() -> Self {
return self.init()
}
}
Then you can call let myViewController = MyViewController.create(). However, unless you want to do something special in that create function it's a bit unnecessary.

how to make a singleton uiviewcontroller class in Swift? [duplicate]

I know how to create singleton class in swift. The best and easy way to create singleton class is the following:
class Singleton {
static let sharedInstance = Singleton()
}
But I don't need singleton for any normal class. I need to create singleton for a viewcontroller class. So I'm using this code create singleton
class AViewController:UIViewController {
static let sharedInstance = AViewController()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
it gives me error near AViewController()
Missing argument for parameter 'coder' in call
Looks like it want me to initialize with init(coder: NSCoder). But what parameter or value should I pass through the coder?
If you really wanted to have singleton for a view controller corresponding to some scene, you'd probably do something like:
class SecondViewController: UIViewController {
static let shared = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Foo")
}
In this example, the storyboard was Main.storyboard and the storyboard identifier for the scene in question was Foo. Obviously, replace those values for whatever was appropriate in your case.
Then your other view controller that was invoking this could do something like:
#IBAction func didTapButton(_ sender: Any) {
let controller = SecondViewController.shared
show(controller, sender: self)
}
I wouldn't recommend singletons for view controllers. View controllers (and their views) should be created when needed and be allowed to be deallocated when they're dismissed. And you're losing many storyboard benefits (by which you see the logical flow between scenes with segues between them). And, if you use this view controller in different contexts, you're inviting problems stemming from the view controller hierarchy falling out of sync with the view hierarchy. I really would discourage you from using singletons for view controllers.
But if you were going to do it, you could do something like that...
Try to do:
AppDelegate:
Add a reference to the ViewController, so you can access it globally, like so:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
private var viewController: ViewController?
func getViewController() -> ViewController {
if viewController == nil {
// make sure that the name of the storyboard is "Main"
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// make sure that you named the viewcontroller in storyboard (Storyboard ID), it is the identifier
viewController = storyboard.instantiateViewController(withIdentifier: "ViewControllerStoryboardID") as! ViewController
}
return viewController!
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// ....
}
AnotherViewController (Usage):
Now you can access it via "AppDelegate", like so:
class AnotherViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let vc = appDelegate.getViewController()
}
// ...
}
Hope this helped.
I would recommend something like:

Create singleton of a viewcontroller in swift 3

I know how to create singleton class in swift. The best and easy way to create singleton class is the following:
class Singleton {
static let sharedInstance = Singleton()
}
But I don't need singleton for any normal class. I need to create singleton for a viewcontroller class. So I'm using this code create singleton
class AViewController:UIViewController {
static let sharedInstance = AViewController()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
it gives me error near AViewController()
Missing argument for parameter 'coder' in call
Looks like it want me to initialize with init(coder: NSCoder). But what parameter or value should I pass through the coder?
If you really wanted to have singleton for a view controller corresponding to some scene, you'd probably do something like:
class SecondViewController: UIViewController {
static let shared = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Foo")
}
In this example, the storyboard was Main.storyboard and the storyboard identifier for the scene in question was Foo. Obviously, replace those values for whatever was appropriate in your case.
Then your other view controller that was invoking this could do something like:
#IBAction func didTapButton(_ sender: Any) {
let controller = SecondViewController.shared
show(controller, sender: self)
}
I wouldn't recommend singletons for view controllers. View controllers (and their views) should be created when needed and be allowed to be deallocated when they're dismissed. And you're losing many storyboard benefits (by which you see the logical flow between scenes with segues between them). And, if you use this view controller in different contexts, you're inviting problems stemming from the view controller hierarchy falling out of sync with the view hierarchy. I really would discourage you from using singletons for view controllers.
But if you were going to do it, you could do something like that...
Try to do:
AppDelegate:
Add a reference to the ViewController, so you can access it globally, like so:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
private var viewController: ViewController?
func getViewController() -> ViewController {
if viewController == nil {
// make sure that the name of the storyboard is "Main"
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// make sure that you named the viewcontroller in storyboard (Storyboard ID), it is the identifier
viewController = storyboard.instantiateViewController(withIdentifier: "ViewControllerStoryboardID") as! ViewController
}
return viewController!
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// ....
}
AnotherViewController (Usage):
Now you can access it via "AppDelegate", like so:
class AnotherViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let vc = appDelegate.getViewController()
}
// ...
}
Hope this helped.
I would recommend something like:

Custom init for UIViewController in Swift with interface setup in storyboard

I'm having issue for writing custom init for subclass of UIViewController, basically I want to pass the dependency through the init method for viewController rather than setting property directly like viewControllerB.property = value
So I made a custom init for my viewController and call super designated init
init(meme: Meme?) {
self.meme = meme
super.init(nibName: nil, bundle: nil)
}
The view controller interface resides in storyboard, I've also make the interface for custom class to be my view controller. And Swift requires to call this init method even if you are not doing anything within this method. Otherwise the compiler will complain...
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
The problem is when I try to call my custom init with MyViewController(meme: meme) it doesn't init properties in my viewController at all...
I was trying to debug, I found in my viewController, init(coder aDecoder: NSCoder) get called first, then my custom init get called later. However these two init method return different self memory addresses.
I'm suspecting something wrong with the init for my viewController, and it will always return self with the init?(coder aDecoder: NSCoder), which, has no implementation.
Does anyone know how to make custom init for your viewController correctly ?
Note: my viewController's interface is set up in storyboard
here is my viewController code:
class MemeDetailVC : UIViewController {
var meme : Meme!
#IBOutlet weak var editedImage: UIImageView!
// TODO: incorrect init
init(meme: Meme?) {
self.meme = meme
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func viewDidLoad() {
/// setup nav title
title = "Detail Meme"
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
editedImage = UIImageView(image: meme.editedImage)
}
}
As it was specified in one of the answers above you can not use both and custom init method and storyboard.
But you still can use a static method to instantiate ViewController from a storyboard and perform additional setup on it.
It will look like this:
class MemeDetailVC : UIViewController {
var meme : Meme!
static func makeMemeDetailVC(meme: Meme) -> MemeDetailVC {
let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "IdentifierOfYouViewController") as! MemeDetailVC
newViewController.meme = meme
return newViewController
}
}
Don't forget to specify IdentifierOfYouViewController as view controller identifier in your storyboard. You may also need to change the name of the storyboard in the code above.
You can't use a custom initializer when you initialize from a Storyboard, using init?(coder aDecoder: NSCoder) is how Apple designed the storyboard to initialize a controller. However, there are ways to send data to a UIViewController.
Your view controller's name has detail in it, so I suppose that you get there from a different controller. In this case you can use the prepareForSegue method to send data to the detail (This is Swift 3):
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "identifier" {
if let controller = segue.destinationViewController as? MemeDetailVC {
controller.meme = "Meme"
}
}
}
I just used a property of type String instead of Meme for testing purposes. Also, make sure that you pass in the correct segue identifier ("identifier" was just a placeholder).
As #Caleb Kleveter has pointed out, we can't use a custom initializer while initialising from a Storyboard.
But, we can solve the problem by using factory/class method which instantiate view controller object from Storyboard and return view controller object.
I think this is a pretty cool way.
Note: This is not an exact answer to question rather a workaround to solve the problem.
Make class method, in MemeDetailVC class, as follows:
// Considering your view controller resides in Main.storyboard and it's identifier is set to "MemeDetailVC"
class func `init`(meme: Meme) -> MemeDetailVC? {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MemeDetailVC") as? MemeDetailVC
vc?.meme = meme
return vc
}
Usage:
let memeDetailVC = MemeDetailVC.init(meme: Meme())
One way that I've done this is with a convenience initializer.
class MemeDetailVC : UIViewController {
convenience init(meme: Meme) {
self.init()
self.meme = meme
}
}
Then you initialize your MemeDetailVC with let memeDetailVC = MemeDetailVC(theMeme)
Apple's documentation on initializers is pretty good, but my personal favorite is the Ray Wenderlich: Initialization in Depth tutorial series which should give you plenty of explanation/examples on your various init options and the "proper" way to do things.
EDIT: While you can use a convenience initializer on custom view controllers, everyone is correct in stating that you cannot use custom initializers when initializing from the storyboard or through a storyboard segue.
If your interface is set up in the storyboard and you're creating the controller completely programmatically, then a convenience initializer is probably the easiest way to do what you're trying to do since you don't have to deal with the required init with the NSCoder (which I still don't really understand).
If you're getting your view controller via the storyboard though, then you will need to follow #Caleb Kleveter's answer and cast the view controller into your desired subclass then set the property manually.
There were originally a couple of answers, which were cow voted and deleted even though they were basically correct. The answer is, you can't.
When working from a storyboard definition your view controller instances are all archived. So, to init them it's required that init?(coder... be used. The coder is where all the settings / view information comes from.
So, in this case, it's not possible to also call some other init function with a custom parameter. It should either be set as a property when preparing the segue, or you could ditch segues and load the instances directly from the storyboard and configure them (basically a factory pattern using a storyboard).
In all cases you use the SDK required init function and pass additional parameters afterwards.
Swift 5
You can write custom initializer like this ->
class MyFooClass: UIViewController {
var foo: Foo?
init(with foo: Foo) {
self.foo = foo
super.init(nibName: nil, bundle: nil)
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.foo = nil
}
}
UIViewController class conform to NSCoding protocol which is defined as:
public protocol NSCoding {
public func encode(with aCoder: NSCoder)
public init?(coder aDecoder: NSCoder) // NS_DESIGNATED_INITIALIZER
}
So UIViewController has two designated initializer init?(coder aDecoder: NSCoder) and init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?).
Storyborad calls init?(coder aDecoder: NSCoder) directly to init UIViewController and UIView,There is no room for you to pass parameters.
One cumbersome workaround is to use an temporary cache:
class TempCache{
static let sharedInstance = TempCache()
var meme: Meme?
}
TempCache.sharedInstance.meme = meme // call this before init your ViewController
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
self.meme = TempCache.sharedInstance.meme
}
As of iOS 13 you can initialize the view controller that resides in a storyboard using:
instantiateViewController(identifier:creator:) method on the UIStoryboard instance.
tutorial:
https://sarunw.com/posts/better-dependency-injection-for-storyboards-in-ios13/
Although we can now do custom init for the default controllers in the storyboard using instantiateInitialViewController(creator:) and for segues including relationship and show.
This capability was added in Xcode 11 and the following is an excerpt from the Xcode 11 Release Notes:
A view controller method annotated with the new #IBSegueAction attribute can be used to create a segue’s destination view controller in code, using a custom initializer with any required values. This makes it possible to use view controllers with non-optional initialization requirements in storyboards. Create a connection from a segue to an #IBSegueAction method on its source view controller. On new OS versions that support Segue Actions, that method will be called and the value it returns will be the destinationViewController of the segue object passed to prepareForSegue:sender:. Multiple #IBSegueAction methods may be defined on a single source view controller, which can alleviate the need to check segue identifier strings in prepareForSegue:sender:. (47091566)
An IBSegueAction method takes up to three parameters: a coder, the sender, and the segue’s identifier. The first parameter is required, and the other parameters can be omitted from your method’s signature if desired. The NSCoder must be passed through to the destination view controller’s initializer, to ensure it’s customized with values configured in storyboard. The method returns a view controller that matches the destination controller type defined in the storyboard, or nil to cause a destination controller to be initialized with the standard init(coder:) method. If you know you don’t need to return nil, the return type can be non-optional.
In Swift, add the #IBSegueAction attribute:
#IBSegueAction
func makeDogController(coder: NSCoder, sender: Any?, segueIdentifier: String?) -> ViewController? {
PetController(
coder: coder,
petName: self.selectedPetName, type: .dog
)
}
In Objective-C, add IBSegueAction in front of the return type:
- (IBSegueAction ViewController *)makeDogController:(NSCoder *)coder
sender:(id)sender
segueIdentifier:(NSString *)segueIdentifier
{
return [PetController initWithCoder:coder
petName:self.selectedPetName
type:#"dog"];
}
In XCode 11/iOS13, you can use
instantiateViewController(identifier:creator:)
also without segues:
let vc = UIStoryboard(name: "StoryBoardName", bundle: nil).instantiateViewController(identifier: "YourViewControllerIdentifier", creator: {
(coder) -> YourViewController? in
return YourViewController(coder: coder, customParameter: "whatever")
})
present(vc, animated: true, completion: nil)
Disclaimer: I do not advocate for this and have not thoroughly tested its resilience, but it is a potential solution I discovered while playing around.
Technically, custom initialization can be achieved while preserving the storyboard-configured interface by initializing the view controller twice: the first time via your custom init, and the second time inside loadView() where you take the view from storyboard.
final class CustomViewController: UIViewController {
#IBOutlet private weak var label: UILabel!
#IBOutlet private weak var textField: UITextField!
private let foo: Foo!
init(someParameter: Foo) {
self.foo = someParameter
super.init(nibName: nil, bundle: nil)
}
override func loadView() {
//Only proceed if we are not the storyboard instance
guard self.nibName == nil else { return super.loadView() }
//Initialize from storyboard
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let storyboardInstance = storyboard.instantiateViewController(withIdentifier: "CustomVC") as! CustomViewController
//Remove view from storyboard instance before assigning to us
let storyboardView = storyboardInstance.view
storyboardInstance.view.removeFromSuperview()
storyboardInstance.view = nil
self.view = storyboardView
//Receive outlet references from storyboard instance
self.label = storyboardInstance.label
self.textField = storyboardInstance.textField
}
required init?(coder: NSCoder) {
//Must set all properties intended for custom init to nil here (or make them `var`s)
self.foo = nil
//Storyboard initialization requires the super implementation
super.init(coder: coder)
}
}
Now elsewhere in your app you can call your custom initializer like CustomViewController(someParameter: foo) and still receive the view configuration from storyboard.
I don't consider this a great solution for several reasons:
Object initialization is duplicated, including any pre-init properties
Parameters passed to the custom init must be stored as optional properties
Adds boilerplate which must be maintained as outlets/properties are changed
Perhaps you can accept these tradeoffs, but use at your own risk.
Correct flow is, call the designated initializer which in this case is the init with nibName,
init(tap: UITapGestureRecognizer)
{
// Initialise the variables here
// Call the designated init of ViewController
super.init(nibName: nil, bundle: nil)
// Call your Viewcontroller custom methods here
}
This solution shows a way to have custom initializers but still be able to use Storyboard WITHOUT using the self.init(nib: nil, bundle: nil) function.
To make it possible to use that, let’s first tweak our MemeDetailsVC to also accept an NSCoder instance as part of its custom initializer, and to then delegate that initializer to super.init(coder:), rather than its nibName equivalent:
class MemeDetailVC : UIViewController {
var meme : Meme!
#IBOutlet weak var editedImage: UIImageView!
init?(meme: Meme, coder: NSCoder) {
self.meme = meme
super.init(coder: aDecoder)
}
#available(*, unavailable, renamed: "init(product:coder:)")
required init?(coder: NSCoder) {
fatalError("Invalid way of decoding this class")
}
override func viewDidLoad() {
title = "Detail Meme"
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
editedImage = UIImageView(image: meme.editedImage)
}
}
And then, you instantiate & show the View Controller this way:
guard let viewController = storyboard?.instantiateViewController(
identifier: "MemeDetailVC",
creator: { coder in
MemeDetailVC(meme: meme, coder: coder)
}
) else {
fatalError("Failed to create Product Details VC")
}
//Then you do what you want with the view controller.
present(viewController, sender: self)
// View controller is in Main.storyboard and it has identifier set
Class B
class func customInit(carType:String) -> BViewController
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let objClassB = storyboard.instantiateViewController(withIdentifier: "BViewController") as? BViewController
print(carType)
return objClassB!
}
Class A
let objB = customInit(carType:"Any String")
navigationController?.pushViewController(objB,animated: true)

Resources