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 a few things to keep in mind:
- 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. - The class must inherit from
NSObject
or any descendant in order to be available in Objective-C. You can skip intermediateswiftyLoad
andswiftyInitialize
callbacks and do the work straight in Objective-C. IfFoo
cannot inherit fromNSObject
you can get away with an intermediateFooObjC
proxying class, which will invoke necessary callback withinFoo
. The solution is pretty flexible, you get the idea! - 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'
inOTHER_LDFLAGS
when linked. Static library might also require-ObjC
inOTHER_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. 🦊🙄