Using NSObject’s +load and +initialize from Swift

Ian Bytchek
Post-Mortem
Published in
2 min readDec 3, 2017

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 a few things to keep in mind:

  1. Starting from Swift 5 class extensions and categories on Swift classes are not allowed to have +load methods, +initialize doesn’t seem to be prohibited, though.
  2. The class must inherit from NSObject or any descendant in order to be available in Objective-C. 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!
  3. 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. 🦊🙄

--

--