Context
I am working on an existing Xcode project that utilizes SPM to manage several internal packages, among other things, that are used within an iOS application.
One of the internal packages contains Objective-C code that defines several extensions of objects and are imported throughout the application.
This package is no longer being actively developed, so I would like to embed it within the iOS application to reduce the compiler workload during a clean build.
Goal
To binarily link a static library that contain object extensions used throughout an existing application in order to reduce compile time.
What I have tried
First, I started by setting up and creating the external project to house the internal package
#import "SomeExtension.hAfter this, I moved on to linking it to the main application using the following process:
#import <ExtensionLibrary.h>Errors
There are two main errors that appear in the main application after doing this process.
Additional Notes
The main iOS application has the Other Linker flags -ObjC and -all_load set.
The main iOS applications app delegate is written in Objective-C.
The main iOS application is a combination of Swift and Objective-C code, both of which use the extensions defined in the ExtensionLibrary.
The cost to refactor existing code within the main iOS application using the extensions provided in the ExtensionLibrary would be very high, so the linked library needs to work with the existing application with as little changes as possible.
The ExtensionLibrary may undergo future development, so the process to re-link the library should be easily repeatable for future developers who have no experience with this process.
Examples of objects being extended: UIApplication, UIView, UIFont, NSDate, NSArray, and NSError
Question
The main question I have is how do I create and embed a static library of globally available Objective-C extensions into an existing iOS application written in Objective-C and Swift?
Frankly from the steps you provided I can't spot any specific issue. The only part I would do different is the universal binary, since I just can't see a reason to do that (yes, it will require you to re-compile the library when you switch to another platform, but only once. Also you will have "less fat" final binary and freedom to change the source code of it on the fly). Let me just sum up all steps with instructions below:
Our sample project is the iOS project template built by Xcode 13 for iOS applications in Objective-C with the following file structure:

Provided the IDE used is Xcode, the steps to create a project as part of another project are as follows:



You should end up with the project structure similar to this:

It's not necessary but for static libs I'm used to make one "master header" which has all other library interfaces included (similar to the umbrella headers for frameworks) with the name of the said lib (SLProject.h in this case), so I remove the implementation file for it (SLProject.m) as well as content of the header itself for now (there is nothing to include). Now, let's create a little category for UIView which prints out the view itself and all other views in the hierarchy (if available):
@import UIKit;
NS_ASSUME_NONNULL_BEGIN
@interface UIView (PrintHierarchy)
- (void)tdw_printHierarchy;
@end
NS_ASSUME_NONNULL_END
#import "UIView+PrintHierarchy.h"
@implementation UIView (PrintHierarchy)
- (void)tdw_printHierarchy {
NSLog(@"%@", self);
if (self.superview) {
[self.superview tdw_printHierarchy];
}
}
@end
Next, I include this feature in my "master header":
#import "UIView+PrintHierarchy.h"
And ensure that all headers are included in the Copy Files phase of the static library target:

Now go to the main project target's Build Phases.

-ObjC flag to the main project's target linker options under Build Settings

For Objective-C part that is it! From here you just import the static library headers wherever you need to and use the methods defined there:
#import <SLProject/SLProject.h>
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view tdw_printHierarchy];
}
@end
In order to provide access to the same library for Swift classes, it's enough to just add this "master header" to the bridging header in your project:
#import <SLProject/SLProject.h>
And now everything is just made available to the Swift classes as well without any extra imports:
import UIKit
class SwiftView: UIView {
func someMethod() {
tdw_printHierarchy();
}
}
Feel free to use the project created while I was writing these instructions here as a reference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With