How to show my cocoa touch framework storyboard screen? - ios

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

Related

How to embed a navigation controller inside a custom framework

I have created a custom framework with storyboard. However eventhough the root viewcontroller been embedded froma navigation controller, every time i check "self.navigationController" it prints "nil". What am I missing here.
However my objective is to pop back to the root viewController once I click a button from my 4th VC. currently the implementation as follows
My Custom Storyboard looks like bellow.
How I navigate as bellow.
if let urlString = Bundle.main.path(forResource: "FAUMESDK", ofType: "framework", inDirectory: "Frameworks") {
let bundle = (Bundle(url: NSURL(fileURLWithPath: urlString) as URL))
let sb = UIStoryboard(name: "FAUMEStoryboard", bundle: bundle)
let vc = sb.instantiateViewController(withIdentifier: "MessagePriviewVC")
vc.modalPresentationStyle = .fullScreen
self.show(vc, sender: nil)
}
I tried with the bellow code but didnt work
let vc = self.storyboard?.instantiateViewController(
withIdentifier: "MyVCIdentifier") as! MessagePreviewUIViewController
self.navigationController?.pushViewController(vc, animated: true)
The way I'm trying to pop back to the rootVC as below (currently its not working, and this is where I need a solution).
navigationController?.popToRootViewController(animated: true)
What am I missing here ???
Although you have embedded your view controller in a navigation controller in your storyboard, you are requesting a specific view controller by its identifier; so you get just that view controller, not that view controller embedded in a UINavigationController.
If you use instantiateInitialViewController then you will get the navigation controller that is the entry point to your storyboard, and it's root view controller will be your MessagePreviewViewController (Assuming that is the name of the view controller immediately after the navigation controller in your storyboard)
if let urlString = Bundle.main.path(forResource: "FAUMESDK", ofType: "framework", inDirectory: "Frameworks") {
let bundle = (Bundle(url: NSURL(fileURLWithPath: urlString) as URL))
let sb = UIStoryboard(name: "FAUMEStoryboard", bundle: bundle)
let vc = sb.instantiateInitialViewController()
vc.modalPresentationStyle = .fullScreen
self.show(vc, sender: nil)
}

Accessing storyboard from custom framework not working

Hi I have to access storyboard from custom framework (LoginUIModule, LoginUIModule have storyboard LoginScreen.storyboard) in app delegate.
I removed Main storyboard from Main Interface and also removed name from Main storyboard file base name as well from .plist, but I getting an error
reason: 'Could not find a storyboard named 'LoginScreen' in bundle NSBundle
Note:- LoginUIModule is separate Module and I need to access it in my main (OneAppllbs) project which is a again separate module
The Code which I used in app delegate
import LoginUIModule
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "LoginScreen", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginUIModuleViewController") as? LoginUIModuleViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
You need set Bundle to access Storyboard.
First create storyboardBundle with Bundle Identifier for framework;
let storyboardName = "LoginScreen"
let storyboardBundle = Bundle(for: LoginUIModuleViewController.self)
or referencing a class in framework:
let storyboardBundle = Bundle(identifier: "com.yourframework.id")
Then create storyboard with this bundle:
let storyboard = UIStoryboard(name: storyboardName, bundle: storyboardBundle)
Get storyboard from a framework
Set Storyboard ID for .storyboard. For example frameworkStoryboardId
[Access to Framework bundle]
let frameworkStoryboard = UIStoryboard(name: "SomeViewController", bundle: frameworkBundle)
let frameworkViewController = frameworkStoryboard.instantiateViewController(withIdentifier: "frameworkStoryboardId") as? SomeViewController

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

Resources