选择器未触发委托方法

Delegate method not being triggered by selector

我将 Class A 中的选择器传递给 Class B 中的方法,最终触发 Class A 中的 PressedButtonForMethodA 委托方法。但是,我认为我的选择器有问题,因为委托方法或 ClassB 的 PressedButtonForMethodA()(ClassB.PressedButtonForMethodA() 仅用于调试目的)都没有被执行。使用 Swift 3 且没有故事板。这是我在 swift 操场上拥有的东西:

import UIKit
import PlaygroundSupport

class classA: UIViewController, ClassBDelegate {
    private func setNavbarButtons() {
        let myBarButton = classB()
        myBarButton.delegate = self
        let myBarButtonItem = myBarButton.setup("Press This", #selector(PressedButtonForMethodA))
        self.navigationItem.rightBarButtonItem = myBarButtonItem
    }

    func PressedButtonForMethodA() {
        NSLog("Method A in Class A fired!") // <<--THIS METHOD NOT BEING CALLED
    }
}

protocol ClassBDelegate {
    func PressedButtonForMethodA()
}

class classB: UIView {
    var delegate: ClassBDelegate?
    func setup(_ title: String, _ selectorAction: Selector) -> UIBarButtonItem {

        let shadow = NSShadow()
        shadow.shadowColor = UIColor.clear

        let attributesNormal = [
            NSForegroundColorAttributeName : UIColor.white,
            NSShadowAttributeName : shadow,
            NSFontAttributeName : UIFont.boldSystemFont(ofSize: 12.0)
        ]

        let button = UIButton(type: .custom)
        let buttonTitleAttributesNormal = NSAttributedString(string: title,
                                                             attributes: attributesNormal)
        button.setAttributedTitle(buttonTitleAttributesNormal, for: UIControlState.normal)
        let buttonTextSize = button.intrinsicContentSize
        button.frame = CGRect(x: 0, y: 0, width: buttonTextSize.width, height: buttonTextSize.height)

        button.addTarget(self, action: selectorAction, for: .touchUpInside)
        let barButtonItem = UIBarButtonItem(customView: button)

        return barButtonItem
    }

    func PressedButtonForMethodA() {
        NSLog("Method A in Class B fired!")  // <<-- THIS METHOD NOT FIRED EITHER
        delegate?.PressedButtonForMethodA()
    }
}
let myBarButtonItem = myBarButton.setup("Press This", #selector(PressedButtonForMethodA))

应该是

let myBarButtonItem = myBarButton.setup("Press This", #selector(myBarButton.PressedButtonForMethodA))

在设置方法中,当您应该从 ClassB 传递选择器时,您从 ClassA 传递选择器,因为您在此处添加了 self 作为目标:

button.addTarget(self, action: selectorAction, for: .touchUpInside)

完成编辑:

我对此进行了更多思考,并尝试了几种实现方式,并提出了两个合理的选择。不确定这两种方法是否会被考虑 "better," 但我想我会倾向于方法 #1。我认为它更 self-contained,并且不需要 Delegate 符合。 (忽略我的另一个答案,如果你看到它......我将两者合二为一)。

方法一

classB 是 UIBarButtonItem 的子类。调用 setup() 传递标题、Selector/Action(self 中的函数)和对 self 的引用(将用作按钮操作的目标)。

class ClassAB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        setNavbarButtons()
    }

    private func setNavbarButtons() {

        let myBarButton = classB()

        myBarButton.setup("Press Me AB", #selector(ClassAB.PressedButtonForMethodAB), self)

        self.navigationItem.rightBarButtonItem = myBarButton

    }

    func PressedButtonForMethodAB() {
        NSLog("Method AB in Class AB fired!")
    }

}

class classB: UIBarButtonItem {

    func setup(_ title: String, _ selectorAction: Selector, _ target: Any) {

        let shadow = NSShadow()
        shadow.shadowColor = UIColor.clear

        let attributesNormal = [
            NSForegroundColorAttributeName : UIColor.white,
            NSShadowAttributeName : shadow,
            NSFontAttributeName : UIFont.boldSystemFont(ofSize: 12.0)
        ]

        let button = UIButton(type: .custom)
        let buttonTitleAttributesNormal = NSAttributedString(string: title, attributes: attributesNormal)
        button.setAttributedTitle(buttonTitleAttributesNormal, for: UIControlState.normal)
        let buttonTextSize = button.intrinsicContentSize
        button.frame = CGRect(x: 0, y: 0, width: buttonTextSize.width, height: buttonTextSize.height)

        // my navbar is white...
        button.backgroundColor = UIColor.blue

        // target and action both assigned by the creator (in this case, ClassAB)
        button.addTarget(target, action: selectorAction, for: .touchUpInside)

        customView = button

    }

}

方法#2

classC 是 UIBarButtonItem 的子类。调用 setup() 传递标题,并将 self 指定为 classC 的委托。在 classC 内部,按钮 Action 是一个 class-level func,它依次调用定义的委托函数。

class ClassAC: UIViewController, ClassCDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        setNavbarButtons()
    }

    private func setNavbarButtons() {

        let myBarButton = classC()

        myBarButton.setup("Press Me AC")

        myBarButton.delegate = self

        self.navigationItem.rightBarButtonItem = myBarButton

    }

    func PressedButtonForMethodAC() {
        NSLog("Method AC in Class AC fired!")
    }
}

protocol ClassCDelegate {
    func PressedButtonForMethodAC()
}

class classC: UIBarButtonItem {

    var delegate: ClassCDelegate?

    func setup(_ title: String) {

        let shadow = NSShadow()
        shadow.shadowColor = UIColor.clear

        let attributesNormal = [
            NSForegroundColorAttributeName : UIColor.white,
            NSShadowAttributeName : shadow,
            NSFontAttributeName : UIFont.boldSystemFont(ofSize: 12.0)
        ]

        let button = UIButton(type: .custom)
        let buttonTitleAttributesNormal = NSAttributedString(string: title, attributes: attributesNormal)
        button.setAttributedTitle(buttonTitleAttributesNormal, for: UIControlState.normal)
        let buttonTextSize = button.intrinsicContentSize
        button.frame = CGRect(x: 0, y: 0, width: buttonTextSize.width, height: buttonTextSize.height)

        // my navbar is white...
        button.backgroundColor = UIColor.blue

        // target is self, selector action is inside self... *that* is where we'll call back to the delegate
        button.addTarget(self, action: #selector(classC.classCTap), for: .touchUpInside)

        customView = button

    }

    func classCTap() {
        NSLog("tap inside ClassC ... call back to delegate method")
        delegate?.PressedButtonForMethodAC()
    }

}