15

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?

vale4674
  • 4,161
  • 13
  • 47
  • 72
  • The only obvious difference between your code and mine is that I loaded that nib from within the main code, not from within the framework code, but that was just an accident; it makes no difference. I just rewrote it so that I load the nib from within the framework code and it works fine too. – matt Mar 11 '16 at 15:15
  • @matt I am going to delete everything and create fresh .xib. It could be that Xcode messed somewhere with cached settings. Thank you. – vale4674 Mar 11 '16 at 15:35
  • Sorry I couldn't actually answer the question. Sometimes it helps just to be shown "yes this should work, you're not crazy". :) – matt Mar 11 '16 at 15:45
  • @matt At least I can enjoy the weekend now and tackle this on Monday :) – vale4674 Mar 11 '16 at 15:54

3 Answers3

17

Where to Put Nib Files within a Framework in iOS Project?

Background to my answer:
I was trying to export some UITableView related implementation and it had UITableViewCell .xib files packed with it. And they turn into .nib files at the end! ;-) And I was referring to those Nib files as follows:

[[NSBundle mainBundle] loadNibNamed:customCellID owner:nil options:nil];

Explanation:
But here the thing I have done wrong is, I build a static Cocoa Touch Framework and try to use it within another Application. So at the run time what would become the MainBundle? Definitely my UITableView implementation trying to find out that Nib file for the customCellID in within the App's main bundle.

Answer:
So I altered my UITableView implementation's above code snippet as follows:

    NSString *frameworkBundleId = @"com.randika.MyFrameworkBundleIDHere";
    NSBundle *resourcesBundle = [NSBundle bundleWithIdentifier:frameworkBundleId];

    customCell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:customCellID];
    if (customCell == nil) {
       NSArray *nibs = [resourcesBundle loadNibNamed:emptyCellID owner:nil options:nil];
       customCell = [nibs objectAtIndex:0];
    }

And the framework I built out of my UITableView implementation didn't give the above error ever again! :-)

Hope this answer might be helpful to somebody out there!

Cheers! :-)

Community
  • 1
  • 1
Randika Vishman
  • 7,983
  • 3
  • 57
  • 80
3

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()
Entro
  • 119
  • 2
  • 5
1

Simpler way is just self referenceing the bundle.

 let bundle = Bundle(for: type(of: self)) 
Prateek Pande
  • 495
  • 3
  • 12