Using NSObject’s +load and +initialize from Swift

Every once in awhile there comes a time when a class needs to do early autonomous initialisation that doesn’t belong into application launch handlers.

Objective-C runtime has perfect candidates for the job: +load and +initialize, read about both here and here. Unfortunately, neither work with Swift 4 with following override errors:

Error: method ‘load()’ defines Objective-C class method ‘load’, which is not permitted by Swift
Error: method ‘initialize()’ defines Objective-C class method ‘initialize’, which is not permitted by Swift

There’s a very simple solution to that — private Objective-C categories:

There are two gotchas:

  1. The class must inherit from NSObject or any descendant. You can skip intermediate swiftyLoad and swiftyInitialize callbacks and do the work straight in Objective-C. If Foo cannot inherit from NSObject you can get away with an intermediate FooObjC proxying class, which will invoke necessary callback within Foo. The solution is pretty flexible, you get the idea!
  2. This works for free when class is compiled into main executable or framework, but static library will need -force_load '$(BUILT_PRODUCTS_DIR)/libMyProject.a' in OTHER_LDFLAGS when linked. Static library might also require -ObjC in OTHER_LDFLAGS, but I haven’t come across that.

As can see, this is a pretty neat solution without reinventing the wheel. Happy coding! ✌️

P. S. And if you ever need a high-quality and high-performance gif recorder checkout Gifox app, which I happen to work on. 🦊🙄