0

我在我的DrawMenu课堂上调用了一个方法ViewController,它绘制了一个椭圆(当前为圆形)按钮,非常简单。它完美地绘制了按钮,但是如果我点击按钮它会崩溃。

即使我在 中创建了一个ViewController类的实例DrawMenu,并将其用于 'button.addTarget' 中的 'target' 参数,也会发生这种情况

这是代码:

类中定义的按钮方法DrawMenu

func drawButton (superImageView: UIImageView, x_of_origin: CGFloat, y_of_origin: CGFloat, width_of_oval: CGFloat, height_of_oval: CGFloat, actionSelector: Selector, want_to_test_bounds:Bool) {

    var VC = ViewController()

    var button = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
    button.addTarget(VC, action: actionSelector, forControlEvents: UIControlEvents.TouchUpInside) 
    button.frame = CGRect(x: x_of_origin, y: y_of_origin, width: width_of_oval, height: height_of_oval)

    button.clipsToBounds = true
    button.layer.cornerRadius = height_of_oval/2.0 

    if (want_to_test_bounds == true) {
        button.layer.borderColor = UIColor.blackColor().CGColor
        button.layer.borderWidth = 1.0
        superImageView.userInteractionEnabled = true
        superImageView.addSubview(button)

    } else {
        superImageView.userInteractionEnabled = true
        superImageView.addSubview(button)
    }

}

类中调用的方法ViewController

override func viewDidLoad() {
    super.viewDidLoad()

    var drawMenu = DrawMenu()

    drawMenu.drawButton(imageView, x_of_origin: 100, y_of_origin: 150, width_of_oval: 100, height_of_oval: 100, actionSelector: "buttonTap:" as Selector, want_to_test_bounds: true) 
}

buttonTap也在ViewController课堂上:

    func buttonTap(sender:UIButton!){
    println("Button is working")
}

任何帮助表示赞赏。谢谢你

4

2 回答 2

2

在该方法drawButton中,您将目标设置为touchUpInside视图控制器的新实例。该引用在局部变量中创建,drawButton并在该方法退出时被释放。当动作处理程序被触发时,它会尝试调用无效对象上的函数,然后你就会崩溃。

此处使用的正确设计模式是委托 - 为处理程序定义一个协议并让您的视图控制器实现该协议。然后,您可以将视图控制器传递给该drawButton方法 -

首先在 DrawMenu 中定义协议 -

protocol ButtonDelegate:NSObjectProtocol
{
    func buttonTap(sender: UIButton!) -> Void
}

然后你可以在你的drawButton方法中使用协议参考 -

func drawButton (superImageView: UIImageView, x_of_origin: CGFloat, y_of_origin: CGFloat, width_of_oval: CGFloat, height_of_oval: CGFloat, delegate: ButtonDelegate, want_to_test_bounds:Bool) {

    var button = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
    button.addTarget(delegate, action: "buttonTap:", forControlEvents: UIControlEvents.TouchUpInside) 
    button.frame = CGRect(x: x_of_origin, y: y_of_origin, width: width_of_oval, height: height_of_oval)

    button.clipsToBounds = true
    button.layer.cornerRadius = height_of_oval/2.0 

    if (want_to_test_bounds == true) {
        button.layer.borderColor = UIColor.blackColor().CGColor
        button.layer.borderWidth = 1.0
        superImageView.userInteractionEnabled = true
        superImageView.addSubview(button)

    } else {
        superImageView.userInteractionEnabled = true
        superImageView.addSubview(button)
    }

}

最后,确保您ViewController实现了协议 -

class ViewController : UIViewController, ButtonDelegate

ViewController并在创建按钮时传递对实例的引用-

override func viewDidLoad() {
    super.viewDidLoad()

    var drawMenu = DrawMenu()

    drawMenu.drawButton(imageView, x_of_origin: 100, y_of_origin: 150, width_of_oval: 100, height_of_oval: 100, delegate: self, want_to_test_bounds: true) 
}

我建议的其他改进是使该drawButton方法成为静态的类方法,这样您就不需要实例化一个实例DrawMenu来使用它,并且让该方法简单地返回按钮,而不是向该方法传递一个视图来添加按钮。以您拥有它的方式,如果您想进行进一步的更改,很难获得对按钮的引用。以这种方式更改功能还可以轻松地将按钮添加到不是 UIImageViews 的视图

最后,使用 CGRect 而不是传递不同的 x,y,width,height

class func drawButton (frame: CGRect, delegate: ButtonDelegate, showOutline:Bool) -> UIButton {

    var button = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
    button.addTarget(delegate, action: "buttonTap:", forControlEvents: UIControlEvents.TouchUpInside) 
    button.frame = frame
    button.clipsToBounds = true
    button.layer.cornerRadius = frame.size.height/2.0 

    if (showOutline) {
        button.layer.borderColor = UIColor.blackColor().CGColor
        button.layer.borderWidth = 1.0
    }
    return button
}

那你会说——

override func viewDidLoad() {
    super.viewDidLoad()

    var newButton = DrawMenu.drawButton(CGRect(x: 100, y: 150, width: 100, height: 100), 
      delegate: self, 
      showOutline: true) 
    imageView.userInteractionEnabled = true
    imageView.addSubview(newButton)
}
于 2015-09-11T05:23:40.293 回答
0

向按钮添加目标时,设置正确的目标对象很重要。在您的情况下,您必须将 View Controller 对象传递给 drawButton 方法,并且在将目标添加到按钮时必须使用该 ViewController 对象。

因为当一个按钮事件被调用时,它会在那个确切的目标中找到选择器!因此,在您的情况下,当您在方法内实例化 ViewController 对象时,该对象将在方法调用结束时被释放。

func drawButton (superImageView: UIImageView, inViewController: UIViewController, x_of_origin: CGFloat, y_of_origin: CGFloat, width_of_oval: CGFloat, height_of_oval: CGFloat, actionSelector: Selector, want_to_test_bounds:Bool)
{
    var button = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
    button.addTarget(inViewController, action: actionSelector, forControlEvents: UIControlEvents.TouchUpInside)
    button.frame = CGRect(x: x_of_origin, y: y_of_origin, width: width_of_oval, height: height_of_oval)

    button.clipsToBounds = true
    button.layer.cornerRadius = height_of_oval/2.0

    if (want_to_test_bounds == true)
    {
        button.layer.borderColor = UIColor.blackColor().CGColor
        button.layer.borderWidth = 1.0
        superImageView.userInteractionEnabled = true
        superImageView.addSubview(button)

    }
    else
    {
        superImageView.userInteractionEnabled = true
        superImageView.addSubview(button)
    }
}
于 2015-09-11T05:24:00.677 回答