How to create a custom property or method supports for UIAppearance in Swift 4

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

Terms of Service

Privacy Policy

Cookie Policy