This is my code, but not wok:
extension UINavigationBar {
@objc dynamic func applyGradient(colors: [UIColor]) {
print("colors: \(colors)")
}
}
UINavigationBar.appearance().applyGradient(colors: [])
any one knows about that? or I missed something?
I usually don't do a lot with @objc
and dynamic
, and in general try to avoid it as much as possible, but your code works if you remove @objc dynamic
. That said, I'm not sure what the behavior you opt-in when you add that combo to a function inside an extension. So it might also be a bug, but I can't tell for sure.
Another workaround which did work for me is this:
extension UINavigationBar {
@objc final func applyGradient(colors: [UIColor]) {
print("colors: \(colors)")
}
}
I think the issue here is that appearance
returns Self
and UINavigationBar
is not a final class, which doesn't play well with @objc
so it seems. Telling the compiler that your method is final
seems to resolve the lookup issue.
Again I can't tell for sure what's happening, it's just my assumption.
I list all possible code
extension UINavigationBar {
func applyGradient(colors: [UIColor]) {
print("colors: \(colors)")
}
}
work
@objc
not work
@objc dynamic
not work
@objc final
work
Not use extension, but SubClass
class MYNavigationBar: UINavigationBar {
func myApplyGradient(colors: [UIColor]) {
print("colors: \(colors)")
}
}
not work, crash
@objc
not work, crash
@objc dynamic
not work
@objc final
work
Would this solve your problem?
extension UINavigationBar {
@objc dynamic func applyGradient(colors: [UIColor]) {
print("Super colors: \(colors)")
}
}
class MYNavigationBar: UINavigationBar {
@objc override final func applyGradient(colors: [UIColor]) {
super.applyGradient(colors: colors)
print("Sub colors: \(colors)")
}
}
MYNavigationBar.appearance().applyGradient(colors: [])
The problem has been solved by your first reply, thank you!
I am just curious about @objc dynamic
why can't work together.
NSObject
's extension uses dynamic dispatching, UIAppearance
relies on NSInvocation
, and @objc dynamic
seems to have no problem.
Instead, @objc final
works fine, final
means using direct dispatch, but will also register the selector in Objective-C Runtime. This is a bit contradictory to UIAppearance
itself.
Ah, my fault, dynamic
work fine . Not called because my example project does not have a UINavigationBar
, NSInvocation
is registered, but there is no actual set, invocation will not be forwarded, so it will not be called.
There is also another situation where the UIAppearance is not called. The view that is already in the Window will not be called. Only the view that has not been added will implement the UIAppearance setting. For the second case, see https://developer.apple.com/documentation/uikit/uiappearance
@objc final
make the method call once and immediately, but not work for UIAppearance, NSInvocation seem to be abandoned