How to use @objc protocol with optional and extensions at the same time?

只愿长相守 提交于 2019-12-06 13:43:50

I think this is not possible in swift (because of the way it bridges to @objc protocols). But this is a work around(using Obj-c associated objects) to solve the unrecognized selector sent to instance... problem.

fileprivate class AssociatedObject: NSObject {
    var closure: (() -> ())? = nil

    func trigger() {
        closure?()
    }
}

// Keys should be global variables, do not use, static variables inside classes or structs.
private var associatedObjectKey = "storedObject"

protocol CustomProtocol: class {
    func setup()
}

extension CustomProtocol where Self: NSObject {

    fileprivate var associatedObject: AssociatedObject? {
        get {
            return objc_getAssociatedObject(self, &associatedObjectKey) as? AssociatedObject
        }

        set {
            objc_setAssociatedObject(self, &associatedObjectKey, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }


    func setup() {
        let object = AssociatedObject()
        object.closure = { [weak self] in // Do not forget to use weak in order to avoid retain-cycle
            self?.functionToCallIndirectlyWithSelector()
        }

        let selector = #selector(object.trigger)
//      Uncomment next line to test it's functionality
        object.perform(selector)

//      Here, you must add selector to the target which needs to call the selector, for example:
//      refreshControl.addTarget(object, action: selector, forControlEvents: .valueChanged)

        self.associatedObject = object
    }

    func functionToCallIndirectlyWithSelector() {
        print("Function got called indirectly.")
    }
}


class CustomClass: NSObject, CustomProtocol {}

let instance = CustomClass()

instance.setup()

I added Self: NSObject constraint to be able to test it's functionality in playground, I'm not sure if it's necessary or not.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!