Search code examples
xcodecocoaxibnsbundleios-frameworks

How to instantiate NSViewController from a Framework on OS X (i.e. getting the correct bundle)


How can I instantiate a view controller from framework added to my OS X App (this may actually be the same process as iOS, I'm unsure, last time I looked Frameworks where not allowed on iOS but that may have changed)?

Here is the setup:

  • Private framework MyFramework.framework,
  • containing a view controller CustomViewController,
  • with XIB CustomViewController.xib.

What does not work

CustomViewController(nibName: "CustomViewController", bundle:nil) will not work because the resources are not in the App's main bundle (they are in the framework).

What does work

To instantiate view controllers from the framework my App using the following code (it works!) which iterates through all loaded frameworks using NSBundle.allFrameworks() and picks out my framework by comparing the bundleIdentifier,

func findMyFrameworkBundle() -> NSBundle? {
    if let frameworkBundles = NSBundle.allFrameworks() as? [NSBundle] {
        for bundle in frameworkBundles {
            if let identifier = bundle.bundleIdentifier {
                if identifier == "com.Me.MyFramework" {
                    return bundle
                }
            }
        }
    }
    return nil
}

let nibName = "CustomViewController"
let bundle = findMyFrameworkBundle()
let viewController = CustomViewController(nibName:nibName, bundle:bundle)

How to improve?

This seems overly complex which make me think that I must be doing something wrong. Some potential solutions:

  1. Can I change my framework and provide custom initialiser which always instantiates view controller with the correct bundle?

For example,

class CustomViewController : NSViewController {

    init() {

        let bundle = // ... the correct bundle even when used as an embedded framework in an App
        super.init(nibName: "CustomViewController", bundle: bundle)
    }

    // ... other code
}
  1. Is there a better way of providing the correct bundle in my App rather than search through NSBundle.allFrameworks()?

Solution

  • I may have misunderstood your question, but I think standard practice is to use the NSBundle constructor that takes an identifier as its only argument. As in:

    let bundle = NSBundle(identifier: "com.Me.MyFramework")!