如何在协议扩展中使用#selector(myMethodName)? [英] How to use #selector(myMethodName) in a protocol extension?

查看:77
本文介绍了如何在协议扩展中使用#selector(myMethodName)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

protocol LazyUpdateable {
    func waitToDoStuff()
    func myMethodName()
}


extension LazyUpdateable where Self: NSObject {
    func waitToDoStuff() {
        self.performSelector(#selector(myMethodName), withObject: nil, afterDelay: 1.5)
    }

    func myMethodName() {

    }
}

在此更新中,我收到错误Argument of #selector refers to a method that is not exposed to objective c,但是如果我使用旧的Selector("myMethodName"),则会收到警告,要求更改为更好的处理方法.在这种情况下可以使用#selector()吗?我已经尝试过在我的协议上设置@objc的情况,但该方法无法正常工作.

With this update i get the error Argument of #selector refers to a method that is not exposed to objective c, but if i go with the old Selector("myMethodName") i get a warning to change to the better way of doing it. Is it possible to use the #selector() in this case? It won't work with setting @objc on my protocol, i've tried it.

这是一个游乐场,您可以尝试显示它不适用于设置@objc

Here is a playground you can try that shows it does not work with setting @objc

import Foundation
import UIKit
import XCPlayground


@objc protocol LazyUpdatable {
    optional func waitToDoStuff()
    optional func myMethodName()
}

extension LazyUpdatable where Self: UIViewController {
    func waitToDoStuff() {
        self.performSelector(#selector(myMethodName), withObject: nil, afterDelay: 1.5)
    }

    func myMethodName() {
        print("LOL")
    }
}


@objc
class AViewController: UIViewController, LazyUpdatable {
    func start() {
        waitToDoStuff()
    }
}

let aViewController = AViewController()
aViewController.start()

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

推荐答案

使用#selector()或Selector()进行动态调度无法看到您的Swift协议扩展.相反,如果可能,请尝试完全避免使用Objective-C.您可以使用libdispatch达到相同的结果:

Dynamic dispatching using #selector() or Selector() doesn't see your Swift protocol extension. Instead, try avoiding Objective-C altogether, if possible. You can achieve the same result using libdispatch:

protocol LazyUpdatable {

    func waitToDoStuff()
    func myMethodName()
}

extension LazyUpdatable {

    func waitToDoStuff() {
        let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.5 * Double(NSEC_PER_SEC)))
        dispatch_after(dispatchTime, dispatch_get_main_queue()) {
            self.myMethodName()
        }
    }

    func myMethodName() {
        print("Aloha!")
    }
}

class ViewController: UIViewController, LazyUpdatable {

    override func viewDidLoad() {
        super.viewDidLoad()
        waitToDoStuff()
    }
}

当然,这不像使用选择器那样灵活,但是可以让您使用真正的Swift协议扩展.

Granted, this is not as flexible as using selectors, but lets you use real Swift protocol extensions.

如果您希望能够取消调用方法,请尝试以下操作:

If you want to be able to cancel invoking the method call, try the following:

var lazyUpdatableCancelKey = UInt8(0)

protocol LazyUpdatable: class {

    func waitToDoStuff()
    func cancelDoingStuff()
    func myMethodName()
}

extension LazyUpdatable {

    func waitToDoStuff() {
        let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.5 * Double(NSEC_PER_SEC)))
        dispatch_after(dispatchTime, dispatch_get_main_queue()) {
            if let shouldCancel = objc_getAssociatedObject(self, &lazyUpdatableCancelKey) as? Bool where shouldCancel == true {
                return
            }
            self.myMethodName()
        }
    }

    func cancelDoingStuff() {
        objc_setAssociatedObject(self, &lazyUpdatableCancelKey, true, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }

    func myMethodName() {
        print("Aloha!")
    }
}

class ViewController: UIViewController, LazyUpdatable {

    override func viewDidLoad() {
        super.viewDidLoad()
        waitToDoStuff()

        let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.4 * Double(NSEC_PER_SEC)))
        dispatch_after(dispatchTime, dispatch_get_main_queue()) {
            self.cancelDoingStuff()
        }
    }
}

这篇关于如何在协议扩展中使用#selector(myMethodName)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆