Method load() defines Objective-C class method 'load', which is not permitted by Swift 1.2
There is an NSHispster article about method swizzling that touches on this in different context:
Unfortunately, a load class method implemented in Swift is never
called by the runtime, rendering that recommendation an impossibility.
Instead, we're left to pick among second-choice options:
Implement method swizzling in initialize. This can be done safely, so long as you check the type at execution time and wrap the swizzling in
dispatch_once (which you should be doing anyway).Implement method swizzling in the app delegate. Instead of adding method swizzling via a class extension, simply add a method to the app
delegate to be executed when
application(_:didFinishLaunchingWithOptions:) is called. Depending on
the classes you're modifying, this may be sufficient and should
guarantee your code is executed every time.
Link: http://nshipster.com/swift-objc-runtime/
-
More info form dev forums:
Swift 1.1 allowed you to define "+load" methods with "class func
load()", but they were not actually run at startup time of your app
like Objective-C +load methods are. Swift 1.2 bans them to avoid the
impression that this might work.
Link: https://devforums.apple.com/message/1102025#1102025
-
tl;dr initialize()
and didFinishLaunchingWithOptions
seem to be decent places for such things in Swift.
Swift - Objective-C load class method?
Prior to Swift 1.2:
override class func load() {
NSLog("load");
}
EDIT:
As of Swift 1.2 you can no longer override the load
method. Look into the method initialize
instead, it behaves different than load though, it get's called the first time the class is being referenced somewhere rather than on application initial load
How to fix Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift in Swift 4?
- You can also use Singleton solve this problem such as:
static let shared : AudioTools = {
$0.initialize()
return $0
}(AudioTools())
Your Objective-C method--->initialize
override class func initialize(){code here}
change:
func initialize(){code here}
Your method here:
func playSound(fileName:String?) {
code here
}
use in Swift3:
let audioPlayer = AudioTools.playMusic(fileName: fileName)
use in Swift4
let audioPlayer = AudioTools.shared.playMusic(fileName: fileName)
How to run a Swift method of a subclass of an Objective-C class, which has a method with the same name
Try this definition (Swift 3):
override func collectionView(_ collectionView: JSQMessagesCollectionView, messageDataForItemAt indexPath: IndexPath) -> JSQMessageData {
// return your item
}
I used this in my project almost 6 months ago.
P.S. JSQMessagesViewController is deprecated now and no longer maintained. You can use MessageKit instead.
P.P.S. You can learn more about how objective-c methods are imported to Swift here.
Method swizzling in Swift
Objective-C, which uses dynamic dispatch supports the following:
Class method swizzling:
The kind you're using above. All instances of a class will have their method replaced with the new implementation. The new implementation can optionally wrap the old.
Isa-pointer swizzling:
An instance of a class is set to a new run-time generated sub-class. This instance's methods will be replaced with a new method, which can optionally wrap the existing method.
Message forwarding:
A class acts as a proxy to another class, by performing some work, before forwarding the message to another handler.
These are all variations on the powerful intercept pattern, which many of Cocoa's best features rely on.
Enter Swift:
Swift continues the tradition of ARC, in that the compiler will do powerful optimizations on your behalf. It will attempt to inline your methods or use static dispatch or vtable dispatch. While faster, these all prevent method interception (in the absence of a virtual machine). However you can indicate to Swift that you'd like dynamic binding (and therefore method interception) by complying with the following:
- By extending NSObject or using the @objc directive.
- By adding the dynamic attribute to a function, eg
public dynamic func foobar() -> AnyObject
In the example you provide above, these requirements are being met. Your class is derived transitively from NSObject
via UIView
and UIResponder
, however there is something odd about that category:
- The category is overriding the load method, which will normally be called once for a class. Doing this from a category probably isn't wise, and I'm guessing that while it might have worked before, in the case of Swift it doesn't.
Try instead to move the Swizzling code into your AppDelegate's did finish launching:
//Put this instead in AppDelegate
method_exchangeImplementations(
class_getInstanceMethod(UINavigationBar.self, "sizeThatFits:"),
class_getInstanceMethod(UINavigationBar.self, "sizeThatFits_FixedHeightWhenStatusBarHidden:"))
How can I make my framework's code automatically run when the app launches?
Objective-C classes derived from NSObject
have the class methods +initialize
and +load
.
The first one is run the first time you send a message to the class, so it is of no use unless you do something in -application:didFinishLaunchingWithOptions:
as you mentioned.
The second one is called exactly once for each class in the app, even if it is not used:
Discussion
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.
In addition:
A class’s +load method is called after all of its superclasses’ +load
methods.A category +load method is called after the class’s own +load method.
In a custom implementation of load you can therefore safely message
other unrelated classes from the same image, but any load methods
implemented by those classes may not have run yet.
Source: Apple's Official Documentation (NSObject Class Reference).
Perhaps you could place your initialization logic there.
If you are using swift, I don't know of any method.
Related Topics
Open Link to Facebook Page from iOS App
Silent Push Notifications Only Delivered If Device Is Charging And/Or App Is Foreground
Fetching All Contacts in iOS Swift
Uitextview Style Is Being Reset After Setting Text Property
Scale Image in an Uibutton to Aspectfit
Swift: How to Get Substring from Start to Last Index of Character
What Tool(S) How to Use to Produce iPhone App Screencasts
Make Custom Button on Tab Bar Rounded
Simulator Slow-Motion Animations Are Now On
Nehotspothelper Annotations Not Appearing
Warning: Uicollectionviewflowlayout Has Cached Frame Mismatch for Index Path 'Abc'
The Advertisingidentifier and Identifierforvendor Return "00000000-0000-0000-0000-000000000000"
Adding Convenience Initializers in Swift Subclass