linking objective-c categories in a static library

20,118

Solution 1

Check out Building Objective-C static libraries with categories:

Objective-C does not define linker symbols for each function (or method, in Objective-C) - instead, linker symbols are only generated for each class. If you extend a pre-existing class with categories, the linker does not know to associate the object code of the core class implementation and the category implementation. This prevents objects created in the resulting application from responding to a selector that is defined in the category.

To resolve this issue, the target linking against the static library must pass the -ObjC option to the linker. This flag causes the linker to load every object file in the library that defines an Objective-C class or category. While this option will typically result in a larger executable (due to additional object code loaded into the application), it will allow the successful creation of effective Objective-C static libraries that contain categories on existing classes.


Important: For 64-bit and iPhone OS applications, there is a linker bug that prevents -ObjC from loading objects files from static libraries that contain only categories and no classes. The workaround is to use the -all_load or -force_load flags.

Source: @albertamg (linking objective-c categories in a static library)

Solution 2

I have had the same problem. A method defined in a category defined in a subproject resulted in an unrecognized selector exception. (In fact, this manifested as inability to specify an UILabel subclass in Interface Builder; the XIB contained the class shown in IB (UILabel or UIView, depending on what I dragged there), rather than the class that I have typed in, and that looked as a weird XCode bug.)

The solution that worked for me has been to use -force_load:

In the left-hand panel, select your main project (the root item). On the right, you will see PROJECT and TARGETS. Select TARGETS. Go to "Build Settings"(in the upper bar) -- "Linking" -- "Other linker flags" and, assuming your subproject is called XXXXX, add -force_load ${BUILT_PRODUCTS_DIR}/libXXXXX.a there (the item has two subitems, Debug and Release, but you click on this compound item so that if affects both Debug and Release).

Note that -force_load works for a single library, and you may need to specify a separate -force_load for each subproject library.

Share:
20,118
micken
Author by

micken

Updated on July 13, 2020

Comments

  • micken
    micken almost 4 years

    I am developing a plugin for an iOS application. I am compiling it into a .a file which is then used by the main xcode project.

    So far I have create a category of the UIDevice class in this library. When I run the main project using this library it crashes due to an unrecognized selector

    -[UIDevice platform]: unrecognized selector sent to instance

    platform is one of the fuinctions I added via the category.

    So I thought it wasn't linking those functions at all and added a c function to the same file as the UIDevice category then called it from my code .

    This time the main project ran fine... So I thought maybe it was something else i did and removed the C function. But lo and behold it crashed again due to unrecognized selector..

    My questions: Why does xcode ignore the category definition unless I call a function declared in the same file?

    Is there an xcode setting i can change to make it include these methods from the UIDevice category regardless of whether I call a function from that file or not?

    cheers

  • micken
    micken almost 13 years
    Thanks for the quick response! I added the linker flag to both projects but still get the same error. However the filesize of the app is already bigger than it should be so perhaps calling a dummy function is the best solution in this case.
  • albertamg
    albertamg almost 13 years
    @micken Important: For 64-bit and iPhone OS applications, there is a linker bug that prevents -ObjC from loading objects files from static libraries that contain only categories and no classes. The workaround is to use the -all_load or -force_load flags.
  • Javier Soto
    Javier Soto almost 12 years
    Is this bug still present to date?
  • docchang
    docchang over 11 years
    I'm getting an error of "libtool: unknown option character `f' in: -force_load" Any ideas?
  • mon4goos
    mon4goos over 11 years
    It seems like this is no longer an issue with Xcode 4.5.2 and iOS 6.0. Just the -ObjC flag suffices.
  • SilverSideDown
    SilverSideDown about 11 years
    Thank you, this worked for us perfectly. We were tearing our hair out trying to figure out why the method in a category was not being found at runtime. Tried everything else possible. The only way it worked was when the category was defined in the same file as the original class, which was not acceptable because of different file visibility (public vs. project).
  • David Dunham
    David Dunham about 6 years
    This isn't working for me. I am building a Unity plugin. The plugin defines categories on e.g. NSNumber. When I run, I get unrecognized selector sent to instance. I added -Objc when I link my plugin. No change. Am I supposed to have this when building the app? (Alas, I can’t do that.)
  • ejps
    ejps about 6 years
    It doesn't work in my project. I have imported the category header but didn't include the corresponding .m in the target compile sources. Build succeeds but crashes at runtime.