EDIT: Since I wrote this answer, the OP has added "pure Swift" to the question in an edit. However, I am leaving this answer here because it remains the only correct way to do this at the time of this writing. Hopefully, module initialization hooks will be added in Swift 6 or 7 or 8, but as of March 2018, pure Swift is the wrong tool for this use case.
Original answer follows:
Unfortunately, Swift doesn't have any direct equivalent to the old initialize()
and load()
methods, so this can't be done in pure Swift AFAIK. However, if you're not averse to mixing a small amount of Objective-C into your project, this isn't hard to do. Simply make a Swift class that's fully exposed to Objective-C:
class MyInitThingy: NSObject {
@objc static func appWillLaunch(_: Notification) {
print("App Will Launch")
}
}
Then add this short Objective-C file to the project:
#import <Cocoa/Cocoa.h>
static void __attribute__ ((constructor)) Initer() {
// Replace "MyFrameworkName" with your framework's module name.
// You can also just #import <MyFrameworkName/MyFrameworkName-Swift.h>
// and then access the class directly, but that requires the class to
// be public, which pollutes the framework's external interface.
// If we just look up the class and selector via the Objective-C runtime,
// we can keep everything internal.
Class class = NSClassFromString(@"MyFrameworkName.MyInitThingy");
SEL selector = NSSelectorFromString(@"appWillLaunch:");
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:class
selector:selector
name:NSApplicationWillFinishLaunchingNotification
object:nil];
}
With these two pieces of code in place, an app that links against your framework should get "App Will Launch" logged to the console sometime before applicationDidFinishLaunching
is called.
Alternatively, if you already have a public ObjC-visible class in your module, you can do this without having to use the runtime functions, via a category:
public class SomeClass: NSObject {
@objc static func appWillLaunch(_: Notification) {
print("App Will Launch")
}
}
and:
#import <Cocoa/Cocoa.h>
#import <MyFrameworkName/MyFrameworkName-Swift.h>
@interface SomeClass (InternalSwiftMethods)
+ (void)appWillLaunch:(NSNotification *)notification;
@end
@implementation SomeClass (FrameworkInitialization)
+ (void)load {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(appWillLaunch:)
name:NSApplicationWillFinishLaunchingNotification
object:nil];
}
@end