I am trying to make a universal framework, for iOS by following steps specified in this URL: Universal-framework-iOS
I have a viewController class within, that frame
If you're using Universal-framework-iOS all resources (including Nibs and images), will be copied inside a separate bundle (folder) such as MyApp.app/Myframework.bundle/MyNib.nib
.
You need to specify this bundle by passing a NSBundle
object instead of nil
. Your can get your bundle object as follows:
NSString *path = [[NSBundle mainBundle] pathForResource:@"Myframework" ofType:@"bundle"];
NSBundle *resourcesBundle = [NSBundle bundleWithPath:path];
As for images you can just prepend Myframework.bundle/
to their names:
[UIImage imageNamed:@"Myframework.bundle/MyImage"
This also works in Interface Builder.
Finally your users to install/update a framework is a pain, specially with resources, so better try to use CocoaPods.
Try this in main.m
#import "ViewControllerWithinFramework.h" //import this
int main(int argc, char *argv[])
{
@autoreleasepool
{
[ViewControllerWithinFramework class]; //call class function
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
I hope this will work for you.
You need to specify the bundle to search inside for the nib. Otherwise, it just (shallowly) searches your application's resources directory.
- (id)initWithTitle:(NSString *)aTitle
{
// replace 'framework' with 'bundle' for a static resources bundle
NSURL *frameworkURL = [[NSBundle mainBundle] URLForResource:@"myFrameworkName" withExtension:@"framework"];
NSBundle *framework = [NSBundle bundleWithURL:frameworkURL];
self = [super initWithNibName:@"ViewControllerWithinFramework" bundle:framework];
if (self)
{
_viewControllerTitle = aTitle;
}
return self;
}
The simplest way is to use [NSBundle bundleForClass:[self class]]
to get the NSBundle
instance of your framework. This won't enable the ability to get the framework's NSBundle
instance by its Bundle ID but that isn't usually necessary.
The issue with your code is the initWithNibName:@"Name" bundle:nil
gets a file named Name.xib
in the given bundle. Since bundle
is nil
, it looks in the host app's bundle, not your framework.
The corrected code for the OP's issue is this:
/*** Part of implementation of ViewControllerWithinFramework class, which is inside the framework ***/
- (id)initWithTitle:(NSString *)aTitle
{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
self = [super initWithNibName:@"ViewControllerWithinFramework" bundle:bundle];
// ...
return self;
}
The only thing changed is giving the correct bundle
instance.
As an another option you can directly put your xib file into your framework project and can get your nib with calling
Swift 3 and Swift 4
let bundleIdentifier = "YOUR_FRAMEWORK_BUNDLE_ID"
let bundle = Bundle(identifier: bundleIdentifier)
let view = bundle?.loadNibNamed("YOUR_XIB_FILE_NAME", owner: nil, options: nil)?.first as! UIView
Objective-C
NSString *bundleIdentifier = @"YOUR_FRAMEWORK_BUNDLE_ID";
NSBundle *bundle = [NSBundle bundleWithIdentifier:bundleIdentifier];
UIView *view = [bundle loadNibNamed:@"YOUR_XIB_FILE_NAME" owner:nil options:nil];
Unfortunately because iOS does not have an exposed concept of dynamic fragment loading some of NSBundle's most useful functionality is a little hard to get to. What you want to do is register the framework bundle with NSBundle, and from then on you can find the bundle by it's identifier - and the system should be able to correctly find nibs, etc. within that bundle. Remember, a framework is just a kind of bundle.
To make NSBundle "see" your bundle and it's meta information (from it's Info.plist), you have to get it to attempt to load the bundle. It will log an error because there will be no CFPlugin class assigned as a principal class, but it will work.
So for example:
NSArray *bundz = [[NSBundle bundleForClass:[self class]] URLsForResourcesWithExtension:@"framework" subdirectory:nil];
for (NSURL *bundleURL in bundz){
// This should force it to attempt to load. Don't worry if it says it can't find a class.
NSBundle *child = [NSBundle bundleWithURL:bundleURL];
[child load];
}
Once that is done, you can find your framework bundle using bundleWithIdentifier:
, where the identifier is the CFBundleIdentifier in your framework's Info.plist.
If you need to use UINib
directly to load your view controller nib directly at that point, it should be easy to locate the bundle using bundleWithIdentifier:
and give that value to nibWithNibName:bundle:
.