Use Storyboards in Dynamic Framework - ios

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

Related

How to present a view controller from appdelegate xcode 11 swift 5

I have been searching all day on how to present a view controller from within the appdelegate. It appears that in xcode 11 the window property was moved to the scenedelegate which has been confusing me. I want to present a view controller from within the appdelegate from the didReceiveRemoteNotification function so when the user receives a notification it takes them to a separate view controller with information. I have tried to do:
self.window?.rootViewController?.present(LoginViewController(), animated: false, completion: nil)
within the appdelegate which used to work in a previous application of mine but it does not seem to work anymore. Any help would be much appreciated.
I was able to solve this issue by using shared windows to get the window from scenedelegate to present the view controller on.
UIApplication.shared.windows.first?.rootViewController?.present(vc, animated: false, completion: nil)
Best approach to present view controller through app delegate is without falling for hierarchy like below:
if let vc = UIStoryboard(name: "YOURSTORYBOARD", bundle: nil).instantiateViewController(withIdentifier: "YOURVIEWCONTROLLER") as? YOURVIEWCONTROLLER {
if let window = self.window, let rootViewController = window.rootViewController {
var currentController = rootViewController
while let presentController = currentController.presentedViewController {
currentController = presentController
}
currentController.present(vc, animated: true, completion: nil)
}
}

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

Swift opening a new view controller programmatically

I'm working on an workout app. I finished everything now I'm stuck at the details.
So when my workout finishes it needs to open a new view controller which will tell the user that he finished the workout.
I have tried to do it with this code:
var storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
//var vc: UINavigationController = storyboard.instantiateViewControllerWithIdentifier("newViewController") as! UINavigationController
var vc: EndOfWorkout = storyboard.instantiateViewControllerWithIdentifier("newView") as! EndOfWorkout
self.presentViewController(vc, animated: true, completion: nil)
But it opens sometimes and sometimes not. Also when it opens it closes after a short period of time.
I need also at the end that the user is able to go back to the main menu but none of the examples that I tried are working.
Your vc variable might be destroyed by ARC, try setting this instance in a property of your controller.
Something like that :
class MainViewController: UIViewController{
private var vc: EndOfWorkout?
override func viewDidLoad() {
...
vc = storyboard.instantiateViewControllerWithIdentifier("newView") as! EndOfWorkout
}
}

opening a tab bar controller on successful login swift

I am extremely new to swift and storyboards. I have an initial view set which presents the user with login or register options. on the success of my login web service, I am trying to open a tab bar. I am getting into the success of the webservice as I can see the response.
My code for attempting to load the tab bar is as folllows in my initial view controller:
func loadHomeScreen()
{
emailField.text = ""
passwordField.text = ""
self.presentViewController(UIStoryboard.tabbarController()!, animated: true, completion: nil)
}
And at the very bottom of that file, I have the following:
private extension UIStoryboard {
class func mainStoryboard() -> UIStoryboard { return UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()) }
class func tabbarController() -> TabbarController? {
return mainStoryboard().instantiateViewControllerWithIdentifier("TabbarControllerID") as? TabbarController
}
}
And in my storyboard I have given the tabbarcontroller the id above. When I run the app (tested on the simulator for iphone6), I am getting the error 'found nil while unwrapping an Optional value' and this is pointing to the line of code in my loadHome func above (self.presentViewController(UIStoryboard.tabbarController()!, animated: true, completion: nil))
Any help would be appreciated
You could instead instantiate your storyboard like so and the code would look like this under loadHomeScreen():
emailField.text = ""
passwordField.text = ""
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("TabbarControllerID") as! TabbarController
self.presentViewController(vc, animated: true, completion: nil)
You may need to change the bundle to the "mainBundle" as you have in your code, but this should work.
This may not be the optimal solution if your plan is to extend UIStoryboard for instantiating your ViewControllers but I think this might be a little easier/cleaner, depending on how your project is set up.

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