Can I make #selector refer to a closure in Swift?

后端 未结 11 1784
深忆病人
深忆病人 2020-12-09 15:12

I want to make a selector argument of my method refer to a closure property, both of them exist in the same scope. For example,

func backgroundC         


        
相关标签:
11条回答
  • 2020-12-09 15:43

    I tried this for UIBarButtonItem at least:

    private var actionKey: Void?
    
    extension UIBarButtonItem {
    
        private var _action: () -> () {
            get {
                return objc_getAssociatedObject(self, &actionKey) as! () -> ()
            }
            set {
                objc_setAssociatedObject(self, &actionKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    
        convenience init(title: String?, style: UIBarButtonItemStyle, action: @escaping () -> ()) {
            self.init(title: title, style: style, target: nil, action: #selector(pressed))
            self.target = self
            self._action = action
        }
    
        @objc private func pressed(sender: UIBarButtonItem) {
            _action()
        }
    
    }
    

    Then you can do this:

    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Test", style: .plain, action: {
        print("Hello World!")
    })
    
    0 讨论(0)
  • 2020-12-09 15:44

    Swift 5.2.x

    First of all, you need to declare an "easy to use" typealias for your block:

    typealias Completion = () -> ()
    

    Then, you must declare private var to use "as a gate" for your function:

    private var action: Completion?
    

    After that, you should create a function that can be called by your Selector (it accept only string format) and to call private completion:

    @objc func didAction() {
         self.action?()
    }
    

    Finally you can re-write your function (using the new swift syntax) like:

    Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(didAction), userInfo: nil, repeats: false)
    self.action = backToOriginalBackground
    

    P.S.: Remember that your variable (or parameter if you embed it to a function) must be of the same of type declared to your typeAlias so, in our case:

    var backToOriginalBackground: () -> ()
    

    or also:

    var backToOriginalBackground: Completion
    
    0 讨论(0)
  • 2020-12-09 15:45

    No, #selector refers to an Objective-C method.

    You can do something much better though: Add an extension to NSTimer that lets you create a scheduled timer not with a target and selector, but with a closure.

    0 讨论(0)
  • 2020-12-09 15:49

    It is now possible. I've created a gist for block-based selectors in Swift 4.

    https://gist.github.com/cprovatas/98ff940140c8744c4d1f3bcce7ba4543

    Usage:

    UIButton().addTarget(Selector, action: Selector { debugPrint("my code here") }, for: .touchUpInside)`
    
    0 讨论(0)
  • 2020-12-09 15:51

    My solution was to create a class block variable like:

    let completionBlock: () -> () = nil
    

    Create a method which calls this completionBlock:

    func completed(){
        self.completionBlock!()
    }
    

    And inside where I want to put my selector like a block I did:

    func myFunc(){
      self.completionBlock = {//what I want to be done}
      NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: #selector(Myclass.completed), userInfo: nil, repeats: false)
    }
    
    0 讨论(0)
提交回复
热议问题