2015-09-11 3 views
0

Я вызываю метод из моего класса DrawMenu в моем классе ViewController, который рисует овальную (в настоящее время круг) кнопку, довольно просто. Он отлично рисует кнопку, но если я нажимаю кнопку, она сработает.EXC_BAD_ACCESS, когда метод кнопки вызова из другого класса

Это происходит несмотря на то, что я создал экземпляр класса ViewController в DrawMenu, и использовал его для параметра «целевого» в «button.addTarget»

Вот код:

Кнопки Метод определен в 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") 
} 

Любая помощь приветствуется. Thank You

+0

Что такое сообщение об аварии/исключении? – Paulw11

+0

Ваш drawButton устанавливает новый экземпляр вашего ViewController в качестве цели. Вам необходимо передать существующий ViewController в качестве параметра drawButton, чтобы он мог быть целевым – Paulw11

+0

Он сбой в делетете приложения с помощью 'Thead 1: EXC_BAD_ACCESS (code = EXC_1386_GPFLT) .' – user2176152

ответ

1

В методе 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, ширина, высота

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) 
} 
+0

Это имеет смысл, спасибо за то, что вы приложили столько усилий. Очень хорошо объяснено, и спасибо за улучшения. Я продолжаю получать ошибку 'Не могу вызвать 'addTarget' с помощью списка аргументов типа '(ButtonDelegate, action: Selector, forControlEvents: UIControlEvents)'' с 'button.addTarget (delegate, action: actionSelector, forControlEvents: UIControlEvents.TouchUpInside' Am Я пропустил что-то? – user2176152

+1

'NSObjectProtocol' отсутствовал в объявлении протокола – Paulw11

+0

Все работает! Спасибо! – user2176152

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) 
    } 
}