Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using framework classes in NIB files #9

Closed
kringelbach opened this issue Jun 17, 2011 · 8 comments
Closed

Using framework classes in NIB files #9

kringelbach opened this issue Jun 17, 2011 · 8 comments

Comments

@kringelbach
Copy link

When using a class from a Real Framework in a NIB, I get the following error when running the application:

Unknown class MyFrameworkClass in Interface Builder file.

MyFrameworkClass is included in the NIB file as an Object with Custom Class set to MyFrameworkClass. The actual case is that I have implemented a UITextFieldDelegate that is attached to a UITextField. I.e. I do not need any references to it in my source code. The problem persists even if I connect it to an IBOutlet in my View Controller.

If I use the class from my source code, either by allocating an instance or by implementing _keepAtLinkTime as described in http://stackoverflow.com/questions/1725881/unknown-class-myclass-in-interface-builder-file-error-at-runtime everything works fine. This is however not a user friendly interface to the users of the framework.

Are there any better ways to ensure that all framework items used in a NIB is included in the binary? A solution that always includes the entire framework in the binary is not desirable either.

@kstenerud
Copy link
Owner

This is really a linker optimization issue, so any solution will have to involve tricking the linker into keeping that class rather than dropping it.

I did the following in a framework target:

  • Make a custom UIViewController subclass with xib (called MyVC)
  • Make a custom UITextField (called MyTextField)
  • Add a text field into MyVC via the interface builder, using custom class MyTextField
  • Put these into a framework and put the resulting embeddedframework into another project

I then put the following into the final project:

MyVC* vc = [[MyVC alloc] initWithNibName:NSStringFromClass([MyVC class]) bundle:nil];
[self.view insertSubview:vc.view atIndex:0];

This, of course, causes the "Unknown class" failure since the linker optimizes MyTextField away.

I added the following to MyTextField:

+ (void) forceLinkerLoad_
{
}

And added the following to MyVC (which is also in the framework):

+ (void) initialize
{
    [super initialize];
    [MyTextField forceLinkerLoad_];
}

Since MyVC is going to be directly referenced in code by the final project, adding a static reference to MyTextField means that anything that causes linking of MyVC also causes linking of MyTextField, with no special action required by the user of the framework.

@jweinberg
Copy link
Contributor

The other solution is to use -ObjC -all_load in your Other Linker Flags. This will force it to load all classes from the lib.

@kstenerud
Copy link
Owner

You could do that, but doing so will cause bloat in the app's final binary since it loads EVERYTHING, including things you're not using. As well, it's something that users of your framework would have to add to their projects, which is not as clean as having things just work out of the box.

This is somewhat related to another linker optimization problem involving source files that contain only categories and no classes. In this case, the linker will drop the categories and the app will fail if it calls any code in that category. You can get around this by making an empty class in the file. I use a macro to make it easier: https://github.com/kstenerud/Objective-Gems/blob/master/Objective-Gems/LoadableCategory.h

@jweinberg
Copy link
Contributor

Yup, I find the bloat to be minimal though, never really had it make or break a project. The whole system is slightly broken and annoying.

@kringelbach
Copy link
Author

Thanks for your reply. In my case, I do not always have the view controller
as part of the framework, but I will use your suggestion wherever possible.
I would rather avoid including all files from the library as suggested in
the other comments, but I can experiment with the file sizes and reconsider.

2011/6/17 kstenerud <
reply@reply.github.com>

This is really a linker optimization issue, so any solution will have to
involve tricking the linker into keeping that class rather than dropping it.

I did the following in a framework target:

  • Make a custom UIViewController subclass with xib (called MyVC)
  • Make a custom UITextField (called MyTextField)
  • Add a text field into MyVC via the interface builder, using custom class
    MyTextField
  • Put these into a framework and put the resulting embeddedframework into
    another project

I then put the following into the final project:

MyVC* vc = [[MyVC alloc] initWithNibName:NSStringFromClass([MyVC class])
bundle:nil];
[self.view insertSubview:vc.view atIndex:0];

This, of course, causes the "Unknown class" failure since the linker
optimizes MyTextField away.

I added the following to MyTextField:

  • (void) forceLinkerLoad_
    {
    }

And added the following to MyVC (which is also in the framework):

  • (void) initialize
    {
    [super initialize];
    [MyTextField forceLinkerLoad_];
    }

Since MyVC is going to be directly referenced in code by the final project,
adding a static reference to MyTextField means that anything that causes
linking of MyVC also causes linking of MyTextField, with no special action
required by the user of the framework.

Reply to this email directly or view it on GitHub:

#9 (comment)

@kringelbach
Copy link
Author

One more note. I have not seen this problem when using the standard iOS framework, so they must somehow be handled differently.

EDIT: And this is of course because the iOS standard frameworks are part of the OS and loaded dynamically on the device. I will close this issue. Thanks for your suggestions.

@Niko-r
Copy link

Niko-r commented Jan 13, 2016

Hi,

Almost 5 years after your answer, I just want to thank you @kstenerud for sharing your solution with forceLinkerLoad_ .

This was the solution to my issue, I found it nowhere else from here, and you deserve my thanks.

So thank you again ! :-)

@paleozogt
Copy link

Another possibility is to use Xcode's Perform Single-Object Prelink

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants