【问题标题】:Delegate method not being triggered by selector选择器未触发委托方法
【发布时间】:2017-03-21 20:11:53
【问题描述】:

我将 A 类中的选择器传递给 B 类中的方法,以最终触发 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()
    }
}

【问题讨论】:

  • 如果你发布你的实际代码更容易帮助你 - 或者,至少有足够的代码可以使用和测试......
  • 好点,DonMag。刚刚更新以包含我在 swift playground 中的实际代码。

标签: ios swift3 delegates protocols selector


【解决方案1】:

完成编辑:

我对此进行了更多思考,并尝试了几种方法,并提出了两个合理的选择。不确定这两种方法是否会被认为“更好”,但我想我会倾向于方法 #1。我认为它更加独立,并且不需要符合委托。 (忽略我的另一个答案,如果你已经看过的话......我将两者合二为一)。

方法#1

classB 是 UIBarButtonItem 的子类。调用 setup() 传递标题、Selector/Action(self 内部的一个 func)和对 self 的引用(将用作按钮 Action 的目标)。

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 是一个类级别的 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()
    }

}

【讨论】:

  • 方法 2 是一个很好的调用......仍然习惯于 Swift 和 def 应该从 UIBarButtonView 继承 Class B(或您的解决方案中的 Class C)。最终,由于我的目标是触发 ClassA.PressedButtonForMethodA(),我最终将 button.addTarget(self, action: selectorAction, for: touchUpInside) 的 target 属性从 self 更改为 delegate,从而解决了问题。而且,您更改 C 类的父类的解决方案将在两个类中触发该方法。非常感谢您的帮助!
【解决方案2】:
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)

【讨论】:

  • 对,约翰斯莱。我想知道为什么 selectorAction 不调用 delegate?.PressedButtonForMethodA() 让 A 类中的选择器调用该方法的语法是什么样的?我试图让 B 类的 PressedButtonForMethodA() 触发,作为让此功能正常工作的另一种方式,但显然,这也触发了。
  • 哦,我没看到,但是您从 ClassA 传递了一个选择器并尝试从 ClassB 调用选择器,因为您在按钮上将目标设置为 Self
  • 嘿伙计 - 感谢您的帮助。您最后关于使用self 作为目标的解释帮助我弄清楚我需要传入delegate 来触发A 类中的方法。但是,我选择了@donmag 的解决方案,因为它最终解释了更多问题的原因(B 类继承自错误的超类)。再次感谢!
  • NP,我建议使用委托模式并将按钮的操作包含在自身中。如果您从另一个类传递选择器,则可能会发生坏事并导致崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 2018-11-13
  • 2018-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多