Objective‑C categories omitted in release builds due to dead‑code stripping
0 reputation · 29 Nov 2021, 13:02 UTC
0 reputation · 29 Nov 2021, 13:02 UTC
Confirm category methods from a static library are retained in the final binary for production deployments.
In debug builds the app loads the category on NSString and the custom method works. After shipping to the App Store, the same code triggers an unrecognized selector exception. The library is linked normally, but the category object file may be dropped by the linker when it is not referenced directly.
The default linker behavior in release mode performs dead‑code stripping and ignores object files that appear unused, unless the -ObjC or -force_load flags are set. The documentation states that categories are preserved only when the linker is forced to load all Objective‑C symbols.
-ObjC flag be added to every target that imports a static library containing categories, or can we selectively apply it?-force_load versus -ObjC for large libraries?31275 reputation · 29 Nov 2021, 17:32 UTC
To prevent the linker from stripping Objective-C categories from static libraries in release builds, add the -ObjC flag to the Other Linker Flags (OTHER_LDFLAGS) of your main application target. This instructs the linker to load all Objective-C classes and categories from all linked static libraries, regardless of whether they are explicitly referenced in the code.
In Objective-C, categories are added to classes at runtime. Because the static linker only sees references to the base class (e.g., NSString) and not the category methods, it identifies the object files containing those categories as "unreferenced" and strips them to reduce binary size during release builds.
Depending on the size of your dependencies, you may choose between a global or selective approach:
| Flag | Scope | Trade-off |
|---|---|---|
-ObjC |
Global (All static libs) | Simplest configuration; may increase binary size by including unused Objective-C code from all libraries. |
-force_load [path] |
Selective (Specific lib) | Prevents bloat from other libraries; requires maintaining absolute or relative paths to specific .a files. |
-ObjC to the Release configuration.To ensure categories are present before shipping, you can verify the binary using the nm tool. Run the following command in a terminal against your release build product:
nm -arch arm64 "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" | grep "yourCategoryMethodName"
If the command returns no output, the category was stripped. Alternatively, enable Write Link Map File in Build Settings and search the resulting .txt file for the category's object file name to confirm it was included in the final link.
Diagnostic Note: Are you linking these categories via a static library (.a) or a dynamic framework? If using a dynamic framework, this stripping behavior typically does not occur, and the issue may lie in the framework's own internal linking.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.