Extending a Swift class with Objective-C category

后端 未结 3 1950
迷失自我
迷失自我 2020-12-14 16:48

Im in a situation where I need to use Objective-C category to extend a Swift class. I\'ve done something as follows:

In \"SomeClass.swift\":

class So         


        
相关标签:
3条回答
  • 2020-12-14 17:19

    From the Interoperability guide, we cannot directly access the subclassed / categorized / extensioned Objc-objects for the .swift [SomeClass] class.

    But as a turn-around, we can do this:

    For Variables , we can do this:

    extension Class {
        private struct AssociatedKeys {
            static var DescriptiveName = "sh_DescriptiveName"
        }
    
        var descriptiveName: String? {
            get {
                return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
            }
    
            set {
                if let newValue = newValue {
                    objc_setAssociatedObject(
                        self,
                        &AssociatedKeys.DescriptiveName,
                        newValue as NSString?,
                        .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                    )
                }
            }
        }
    }
    

    For Methods, we can use method_swizzling which is not recommended.

    0 讨论(0)
  • 2020-12-14 17:23

    As one simple solution, you can move the extension to your Swift code. Then you won't have any dependency problems.

    0 讨论(0)
  • 2020-12-14 17:24

    The Bad

    i too have been fighting this issue a bunch. unfortunately the documentation pretty explicitly states that this pattern is not allowed:

    To avoid cyclical references, don’t import Swift code into an Objective-C header (.h) file. Instead, you can forward declare a Swift class or protocol to reference it in an Objective-C interface.

    Forward declarations of Swift classes and protocols can only be used as types for method and property declarations.

    also throughout the the linked page you will notice it keeps mentioning to import the generated header specifically into the .m file:

    To import Swift code into Objective-C from the same target

    Import the Swift code from that target into any Objective-C .m file within that target

    The Good

    one solution that may work for you is to create a swift extension that redefines each method you need in the category. it is fragile and ugly, but arguably the cleanest solution.

    /**
     Add category methods from objc here (since circular references prohibit the ObjC extension file)
     */
    extension SomeClass {
        @nonobjc func someMethod() {
            self.performSelector(Selector("someMethod"))
        }
    }
    
    • adding the @noobjc to the front allows the same method signature to be used w/o overriding the ObjC implementation
    • now the import "SomeClass+Extension.h" from the bridging header can be removed

    if support for more than two input params is needed, or tighter type coupling is desired i would recommend using the runtime to call the underlying function. a great description is here.

    0 讨论(0)
提交回复
热议问题