Automatically run Swift code when your framework gets initialized

Β·

2 min read

In this blog post, you'll learn how you can create a framework that executes code automatically when the framework gets initialized as part of the app startup. This can be useful for frameworks that want to run code without requiring the app developer to write some initialization/instrumentation code.

An example would be Dynatrace and its binary framework, which automatically starts data collection without the app developer needing to call a setup or start function.

You will need to write a bit of Objective-C code as you will leverage +load() of NSObject.

The load() message is sent to classes and categories that are both dynamically loaded and statically linked, but only if the newly loaded class or category implements a method that can respond.

The order of initialization is as follows:

  • All initializers in any framework you link to.

  • All +load methods in your image.

  • All C++ static initializers and C/C++ attribute(constructor) functions in your image.

  • All initializers in frameworks that link to you.

You can still write most of your code (i.e. the code to be executed) in Swift and invoke your Swift code from your Objective-C implementation.

I provide an example on GitHub.

The example contains an iOS app implemented in SwiftUI, and its app target embeds MixedFwk, a framework that contains Objective-C and Swift files.

Once the app starts, you can see that the load function of FwkObjcClass in MixedFwk is invoked automatically.

#import "FwkObjcClass.h"
#import "MixedFwk/MixedFwk-Swift.h"

@implementation FwkObjcClass
+(void)load {
    NSLog(@"MixedFwk.FwkObjClass loaded");
    FwkSwiftClass *swiftClass = [[FwkSwiftClass alloc] init];
    [swiftClass doSomeWork];
}
@end

Interoperability between ObjcC and Swift is demonstrated as FwkObjcClass will initialize and call a function of FwkSwiftClass.

import Foundation

@objc public class FwkSwiftClass: NSObject {
    override public init() {
        print("MixedFwk.FwkSwiftClass initialized")
    }

    public func doSomeWork() {
        print("MixedFwk.FwkSwiftClass.doSomeWork called")
    }
}

This interoperability is achieved by using the @obj attribute of the Swift language.

I talk about more details, i.e. how to use an attribute(constructor) as an alternative or if/how this can be replicated for Swift Packages, in my YouTube video.

Did you find this article valuable?

Support Marco Eidinger by becoming a sponsor. Any amount is appreciated!