Where to put .xib file inside framework project?

Viewed 5709

I lost half a day figuring this and I can't see a straight forward solution online.

I created an iOS CocoaTouch Framework. I have some private and public classes in it and it all works fine. The problem is when I add .xib file inside that framework.

Inside my framework I want to instantiate .xib file and the error I am getting is:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/dino/Library/Developer/CoreSimulator/Devices/FEDECDC2-D4EA-441E-B53B-329A5B3DFB7A/data/Containers/Bundle/Application/78CEC01F-4C36-4143-A7D6-DDE6CCAC801B/MyApp.app> (loaded)' with name 'NUInAppMessageView''

I've heard that .xib files can not be contained inside static library but I think they should be able to be used inside the framework.

My framework target contains "Copy Bundle Resources" from before and this .xib file was automatically added when I created it inside framework project.

enter image description here

I've read on a few places that resources should be added in a separate .bundle target but there is no "bundle" option when creating new targets and I believe this is form the old static-library-days.

This is the code I am using to initialize my view (inside the framework):

NSBundle * frameworkBundle = [NSBundle bundleForClass:[self class]]; // fine (not nil)

NUInAppMessageView *view = [[frameworkBundle loadNibNamed:@"NUInAppMessageView" owner:self options:nil] firstObject]; // <-- CRASH

I tried to break this into a more method calls and figured that Nib itself is getting created:

UINib *nib = [UINib nibWithNibName:@"NUInAppMessageView"
                                bundle:frameworkBundle]; // fine (not nil)
NSArray *objects = [nib instantiateWithOwner:self options:nil]; // <-- CRASH

I don't have ideas anymore. I tried with project Clean, deleting derived data but they don't seem to do the job.

Am I missing something here?

3 Answers

Generic solution for controllers with .xib file

public extension UIViewController {

    //** loads instance from right framework bundle, not main bundle as UIViewController.init() does
    private static func genericInstance<T: UIViewController>() -> T {
        return T.init(nibName: String(describing: self), bundle: Bundle(for: self))
    }

    public static func instance() -> Self {
        return genericInstance()
    }
}

Use as

YourViewController.instance()

Simpler way is just self referenceing the bundle.

 let bundle = Bundle(for: type(of: self)) 
Related