Initiating view controller through self.storyboard crash - ios

I am using the storyboard references in my project. When I tried to load view controller using self.storyboard it crashes. But When I created a new instance of storyboard and tried to load it works perfectly.
Another thing is without storyboard reference it works perfectly for the first case also.
I am using Xcode 7.3.1.
With self.storyboard. It crashes
guard let registerViewController = self.storyboard?.instantiateViewControllerWithIdentifier(Sto‌ryboardIdentifier.Re‌gistration) as? RegisterVC else { return }
This is the instance of UIStoryboard. It works.
let mainStoryBoard = UIStoryboard.init(name: "Main", bundle: nil)
guard let registerViewController = mainStoryBoard.instantiateViewControllerWithIdentifier(StoryboardIdentifier.Registration) as? RegisterVC else {
return
}

I'm going to go out on a limb here, since you are using Storyboard References, and say that mainStoryBoard and self.storyboard are referencing different StoryBoards, and the one that chokes does not contain the ViewController named StoryboardIdentifier.Registration.
Either that or StoryboardIdentifier.Registration contains a different value in each case.

Related

Use Storyboards in Dynamic Framework

I am trying to create a dynamic framework in swift.
My Framework contains a ViewController inside a Storyboard.
I am not able to open my ViewController when a push notification comes inside my framework.
However i tried to use the below code :
let bundle = Bundle(identifier: "my_Framework_bundleID")
let frameworkStoryboard: UIStoryboard = UIStoryboard.init(name: "MyFrameworkStoryboard", bundle: bundle)
let viewController = frameworkStoryboard.instantiateViewController(withIdentifier: "MyViewController")
self.present(viewController, animated: true, completion: nil)
Doing this only executes the code inside MyViewController's viewDidLoad method but does not show the loads the UI.
I also tried this:
let bundle = Bundle(identifier: "my_Framework_bundleID")
let controller = UIViewController(nibName: "MyViewController", bundle: bundle)
present(controller, animated: true, completion: nil)
Doing this i get the following error:
Attempt to present UIViewController: 0x135124920 on MyFramework.anotherViewController: 0x133df1a40 whose view is not in the window hierarchy!
self.pushviewController() and self.show() doesn't work as well.
I am stuck in this problem for two days.
I figured out a way to make it work
In the Appdelegate of my app where i am using my framework i passed the instance of rootviewcontroller like this:
test.myFunc(withRootView: (self.window?.rootViewController)!)
Now in my Framework i created a xib and a corresponding UIView file for it.
To navigate to this UIView file i used below code in "myFunc" function.
public func myFunc(withRootView rootview: UIViewController)
let modalView = MyUIViewClass(frame: self.view.bounds)
if rootview.presentedViewController == nil {
rootview.view.addSubview(modalView)
} else {
rootview.presentedViewController?.view.addSubview(modalView)
}

iOS how to start a viewcontroller from framework

I have created my private framework successfully. It has no error. I have created a project now I want a simple thing but I do not have clue. Following is what I want
I want to start the Framework view controller.
You can think it is the whole app. I want to start its first view
controller. and then the app flow is as per business logic. I
want to exit app when user exit the Framework main view controller. Actually it was the complete app but I decided to make it framework for different clients because only small modifications are needed for different clients but I do not know how it should be done.
here is how I am trying to start first view controller in my Client project but it does not recognize that controller.
#IBAction func onClickBtnStartOver(_ sender: Any)
{
let storyBoard : UIStoryboard = UIStoryboard(name: "Storyboard", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("idFrameworkVC") as FwViewController
self.presentViewController(nextViewController, animated:true, completion:nil)
}
It gives me error like "Use of undeclared type 'FwViewController'"
So what should I do to start the first viewcontroller of framework.
Note: I have viewcontrollers in one Storyboard namely Storyboard inside Framework
Declare an open func in your framework for opening first viewController :
open func presentFirstViewControllerOn(_ viewController:UIViewController) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Storyboard", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("idFrameworkVC") as FwViewController
viewController.presentViewController(nextViewController, animated:true, completion:nil)
}
and call this method from client app's VC.
Deciding which is the first VC (if needed) should be the responsibility of the framework, not your client app.
use your framework bundle identifier
let frameworkBundle = Bundle(identifier: "your framework bundle identifier")
let storyboard = UIStoryboard(name: "your framework storyboard name", bundle: frameworkBundle)
let mas = storyboard.instantiateInitialViewController() as! UIViewController
self.present(mas, animated: true, completion: nil)
Try this:
UIApplication.shared.keyWindow?.rootViewController = UIStoryboard(name: "yy", bundle: nil).instantiateInitialViewController()
If everything is setup nicely then you may have not imported your framework in it. This is very important part. Make double check if You have declared Public your framework VC.
Then After it you need to start It in you method.
I will suggest to see this selected answer. And this is the case with you
PS: Do not forget to go through into comments on the selected answer as there is discussion about crash. I doubted that you face them, But if you did encounter any crash then fix the issue using that comment in answer

Setting Init VC in App Delegate?

I am trying to init my core data stack with the init VC of my app. To do this I want to pass the core data manager i have created into the first VC upon loading.
I thought this code would make sense to pass the coredatamanager into the VC, however I get errors whichever way i write this code, im sure im missing something simple?
// Initialize Storyboard
let storyboard = UIStoryboard(name: "RoutineController", bundle: Bundle.main)
// Instantiate Initial View Controller
if let viewController = storyboard.instantiateInitialViewController() as? ViewController {
// Configure View Controller
viewController.coreDataManager = coreDataManager
// Set Root View Controller
window?.rootViewController = viewController
}
Error is simply:
Use of undeclared type 'ViewController'
However if i delete 'as? ViewController' I get an error on the following line that viewController has no property coreDataManager.
Is there some sort of delegate i need to define in the viewdidload of the view controller in sending to?
EDIT Revised my code to correct the storyboard ID, however the code inside the {} doesnt seem to execute, i get the printed error i wrote due to the if let failing, so this still isnt the right way to set the viewController...any ideas as to why?
// Initialize Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// Instantiate Initial View Controller
if let viewController = storyboard.instantiateInitialViewController() as? RoutineController {
// Configure View Controller
print("SENDING THIS INFO TO THE FIRST VC \(self.coreDataManager)")
viewController.coreDataManager = self.coreDataManager
// Set Root View Controller
window?.rootViewController = viewController
} else {
print("WE COULDNT SET VIEWCONTROLLER AS THE DESIGNATED VC SO MOC WASNT PASSED")
}
This is your problem:
as? ViewController
should be
as! UIViewController
alternatively this should also work:
as! RoutineController
Select the RoutineController in your storyboard and set the storyboard ID
Then use the Storyboard ID here:
if let viewController = storyboard.instantiateViewController(withIdentifier: "<storyboardID>") as? RoutineController {
The solution was that you need to define an identifier in the if let viewController to find it successfully, the working code is as follows:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let viewController = storyboard.instantiateViewController(withIdentifier: "TabBarController") as? TabBarController {
viewController.coreDataManager = self.coreDataManager
window?.rootViewController = viewController

Passing value over to next viewController

I am currently writing an app in Swift and I implemented all my UI programatically. I would it kind of exhausting, so recently I decided to use storyboard but I am stuck with a bug.
When passing over the mainContext from the AppDelegate to the FirstViewController, the value of the mainContext is nil. In the first place, when I wrote everything programmatically, my code looked like this:
let vc = FirstViewController()
vc.mainContext = mainContext
window?.rootViewController = vc
But now that I am working with StoryBoard, this is not valid anymore because I have to instantiate the view with its ID, like this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vc = storyboard.instantiateViewControllerWithIdentifier("FirstView") as! FirstViewController
vc.mainContext = mainContext
But in this case, the context is nil. If I don't instantiate the VC like this, my outlets are nil and I get this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Does someone know a way to pass my mainContext?
You're not accessing the rootViewController, you're creating a new view controller and not doing anything with it, to access the rootViewController replace this
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vc = storyboard.instantiateViewControllerWithIdentifier("FirstView") as! FirstViewController
vc.mainContext = mainContext
with
if let vc = self.window?.rootViewController as? FirstViewController {
vc.mainContext = mainContext
}

How to show my cocoa touch framework storyboard screen?

I created a simple Cocoa touch framework with a storyboard. In my framework i have a MainViewController.swift viewcontroller.
I created a new single view project, imported my framework and tried to load my framework viewcontroller, but i got black screen. And I dont know why.
I tried load framework with this code:
let frameworkScreen : UIViewController = MainViewController()
self.presentViewController(frameworkScreen, animated: true, completion: nil)
You need to load the view controller by instantiating it from the storyboard in the framework.
Here's how. First some initial conditions:
Let's say your framework is called Coolness.
Let's say your framework's storyboard is called CoolnessStoryboard.storyboard.
Let's say your framework has a public class called CoolnessViewController.
Let's say that CoolnessStoryboard has a scene whose view controller is CoolnessViewController and that this is its initial view controller.
Then in your main code you would import Coolness and, to present your CoolnessViewController from the storyboard, you would say:
let s = UIStoryboard (
name: "CoolnessStoryboard", bundle: NSBundle(forClass: CoolnessViewController.self)
)
let vc = s.instantiateInitialViewController() as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
Note the strategy here. Work backwards from the goal. We need the instance of CoolnessViewController that is in the storyboard. To get that, we need a reference to that storyboard. To do that, we need to identify that storyboard. How? We can identify it by name and by the bundle that it is in. But how can we identify that bundle? We can identify the bundle by means of a class in that bundle. We have such a class, because we have imported the framework (import Coolness) and the class there is public (so we can speak of it).
I had the same problem. This is how I solved after a little research:
1 - I have a framework called "Messenger.framework"
2 - Inside it, I have a storyboard file called "Messenger.Storyboard"
3- My initial view controller is a UINavigationController with a rootViewController and my ChatController.
So this is how a present my framework's chat UIViewController:
- (void)presentChatController
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Messenger"
bundle:[NSBundle bundleForClass:ChatController.class]];
ChatController *controller = [storyboard instantiateViewControllerWithIdentifier:#"Chat"];
[self.navigationController pushViewController:controller animated:YES];
}
I hope this helps you.
If your framework name is MyFramework, and storyboard name is Main, with a viewcontoller with storyboard id vc
if let urlString = NSBundle.mainBundle().pathForResource("MyFramework", ofType: "framework", inDirectory: "Frameworks") {
let bundle = (NSBundle(URL: NSURL(fileURLWithPath: urlString)))
let sb = UIStoryboard(name: "Main", bundle: bundle)
let vc = sb.instantiateViewControllerWithIdentifier("vc")
self.showViewController(vc, sender: nil)
}
I have inculded the framework using cocoapods.
In Swift 5.5, Xcode 13 and iOS 15
if let urlString = Bundle.main.path(forResource: "MyFramework", ofType: "framework", inDirectory: "Frameworks") {
let bundle = (Bundle(url: NSURL(fileURLWithPath: urlString) as URL))
let sb = UIStoryboard(name: "Main", bundle: bundle)
let vc = sb.instantiateViewController(withIdentifier: "vc")
self.show(vc, sender: nil)
}

Resources