Reputation: 638
I want to distribute a single View Controllers as a framework (called LoginFrameWork.framework) that can be imported and used in any App project. So in XCode I created an iOS Swift Framework project, in which I added a view controller instantiated with a XIB to display a login view (with username, password and button). This LoginViewController is coded with a public interface so that it can included and used from any App.
The framework View Controller is as follows:
public class LoginViewController: UIViewController {
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBAction func signInButton(_ sender: UIButton) {
print("username \(emailTextField.text) password \(passwordTextField.text)")
}
public override func viewDidLoad() {
super.viewDidLoad()
}
}
Next I create an App project MyApp.xcodeproj with a single view controller MyAppVC and a button. When the button is clicked I'd like to push the LoginViewController from the framework created above.
So I create a Workspace called MyApp.xcworkspace. in XCode and add to it LoginFrameWork.framework and MyApp.xcodeproj created above. I hookup the single button on MyAppVC to open LoginViewController.
import UIKit
import LoginFrameWork
class ViewController: UIViewController {
@IBAction func launchLogin(_ sender: Any) {
//LoginSDK.start(presentingVC: self)
var loginVC = LoginViewController(nibName: "LoginViewController", bundle: nil)
// Present
self.present(loginVC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
However this crashes with the error below, which indicates that it cannot find LoginViewController. This could be because either (a)it has the wrong path to LoginViewController in the Library folder OR (b) the framework did not get installed in the devices folder (c) something else ...
(I did include LoginFrameWork.framework in MyApp project the General tab and under the Embedded binaries section)
libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/ramanmtx/Library/Developer/CoreSimulator/Devices/5C88CAFD-85B0-49E2-8641-362D6097DEA6/data/Containers/Bundle/Application/CF14B060-A662-44B7-9CC3-3C7EBD968D21/McApp.app> (loaded)' with name 'LoginViewController''
terminating with uncaught exception of type NSException
CoreSimulator 757.5 - Device: iPhone 12 Pro Max (5C88CAFD-85B0-49E2-8641-362D6097DEA6) - Runtime: iOS 14.5 (18E182) - DeviceType: iPhone 12 Pro Max
Upvotes: 0
Views: 661
Reputation:
Posting this as an answer, more than happy to delete if it doesn't help.
I don't work with NIB/XIB files, so I'm having difficulty duplicating what you are trying, but I still believe I understand the actual issue. It really doesn't have to do with that, but with bundles, and where you are trying to pull things from.
Here's what I do. For example, let's say you have three things:
MyFramework
, which containsMyFile
, and is being used byMyProject
This seems to me what you want. Now, in your case MyProject
imports MyFramework
which contains MyFile
. BUT...
In MyProject
you are trying to access a file that's in the MyFramework
bundle:
var loginVC = LoginViewController(nibName: "LoginViewController", bundle: nil)
Here's what works for me. First, I'm accessing something very different - CoreImage kernel files inside MyFramework
, instantiating things there as CIFilters. Keep that in mind, but I think it's the same thing you want.
In MyFramework
I open the bundle file:
func openBundleFile(_ named:String) -> String {
let myBundle = Bundle.init(identifier: "com.MyCompany.MyFramework")
let kernelPath = (myBundle?.path(forResource: "cikernels", ofType: "bundle"))! + "/" + named + ".cikernel"
do {
return try String(contentsOfFile: kernelPath)
}
catch let error as NSError {
return error.description
}
}
The main thing is the bundle identifier. I don't think this will work inside MyProject
for you, but it may.
But I think the best route to go is to:
LoginViewController
that willOf course, it my be possible that simply putting in the bundle name in your app will work. :-) But it still feels wrong - frameworks should not require hard-coding of this sort!
Upvotes: 1