Приєднайте параметр до кнопки.addЗавдання цілі в Swift


102

Я намагаюся передати додатковий параметр до дії "Клікнути", але не можу розібратися, яким повинен бути синтаксис у Swift.

button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

Будь-який метод, натиснувши кнопку:

func buttonClicked(sender:UIButton)
{
    println("hello")
}

У когось є якісь ідеї?

Спасибі за вашу допомогу.


1
Перейдіть за цим посиланням для детальної відповіді та найкращої практики
Sheetal

Питання не має гарної відповіді, оскільки воно вже описує проблемну архітектуру. Вам не потрібен додатковий параметр. Необхідність додаткового параметра - проблема у вашій архітектурі.
Султан

WARNING TO INTERNET: please check out my answer at the bottom
Містер Хеліс

Відповіді:


170

Не можна передавати власні параметри в. addTarget:Одним із варіантів є встановлення tagвластивості кнопки та робота на основі тегу.

button.tag = 5
button.addTarget(self, action: "buttonClicked:", 
    forControlEvents: UIControlEvents.TouchUpInside)

Або для Swift 2.2 і вище:

button.tag = 5
button.addTarget(self,action:#selector(buttonClicked),
    forControlEvents:.TouchUpInside)

Тепер робимо логіку на основі tagвластивості

@objc func buttonClicked(sender:UIButton)
{
    if(sender.tag == 5){

        var abc = "argOne" //Do something for tag 5
    }
    print("hello")
}

4
Привіт, Якщо я хочу отримати indexPath або клітинку кнопки в tableView, чи це можливо?
НКурапаті

1
Ось підказка: не робіть метод приватним.
OhadM

2
Здається, це лише тип Int. Більш нічого.
scaryguy

2
що робити, якщо я хочу передавати рядок і розділ разом?
Yestay Muratov

3
так що ви знаєте, незважаючи на 118 оновлень (і підрахунок), це неправильний спосіб зробити це
пан Хеліс

79

Якщо ви хочете надіслати додаткові параметри методу buttonClicked, наприклад indexPath або urlString, ви можете підкласифікувати UIButton:

class SubclassedUIButton: UIButton {
    var indexPath: Int?
    var urlString: String?
}

Не забудьте змінити клас кнопки у інспектора ідентичності на підкласиUIButton. Ви можете отримати доступ до параметрів всередині методу buttonClicked, використовуючи sender.indexPathабо sender.urlString.

Примітка: Якщо ваша кнопка знаходиться всередині комірки, ви можете встановити значення цих додаткових параметрів у методі cellForRowAtIndexPath (де створена кнопка).


5
Це був єдиний спосіб, який працював на мене. Але мені цікаво, це анти-візерунок чи ні?
scaryguy

1
Я вважаю, що це найкращий спосіб
Duy Hoang

29

Я вдячний усім, хто говорить, що використовує теги, але насправді потрібно розширити клас UIButton і просто додати туди об’єкт ..

Теги - це безнадійний спосіб цього. Розгорніть такий UIButton (у Swift 4)

import UIKit
class PassableUIButton: UIButton{
    var params: Dictionary<String, Any>
    override init(frame: CGRect) {
        self.params = [:]
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        self.params = [:]
        super.init(coder: aDecoder)
    }
}

тоді ваш дзвінок може бути дзвінким (ПРИМІТКА Двокрапки ":" in Selector(("webButtonTouched:")))

let webButton = PassableUIButton(frame: CGRect(x:310, y:40, width:40, height:40))
webButton.setTitle("Visit",for: .normal)
webButton.addTarget(self, action: #selector(YourViewController.webButtonTouched(_:)), for:.touchUpInside)
webButton.params["myvalue"] = "bob"

то, нарешті, все це тут ловлять

@IBAction func webButtonTouched(_ sender: PassableUIButton) {
    print(sender.params["myvalue"] ?? "")
}

Ви робите це одноразово і використовуєте його протягом усього свого проекту (ви навіть можете зробити так, щоб у дочірнього класу був загальний "об'єкт" і покласти все, що завгодно, у кнопку!). Або скористайтеся наведеним вище прикладом, щоб помістити невичерпну кількість ключових / рядкових парам на кнопку. Дійсно корисно для включення таких речей, як URL, підтвердження методології повідомлення тощо

Окрім того, важливо, щоб SOгромада усвідомлювала це. Існує ціле покоління поганих практик, які перериваються по Інтернету тривожним числом програмістів, які не розуміють / не вчили / пропустили точку концепціяobject extensions


10

Для Swift 3.0 ви можете використовувати наступне

button.addTarget(self, action: #selector(YourViewController.YourMethodName(_:)), for:.touchUpInside)

func YourMethodName(_ sender : UIButton) {
    print(sender.tag)

}

9

Швидкий 4.2

Результат:

testButton.on(.touchUpInside) { (sender, event) in
    // You can use any reference initialized before the code block here
    // You can access self by adding [weak self] before (sender, event)
    // You can then either make self strong by using a guard statement or use a optional operator (?)
    print("user did press test button")
}

У файлі UIButton+Events.swiftя створив метод розширення, UIButtonякий пов'язує UIControl.Eventобробник завершення під назвою EventHandler:

import UIKit

fileprivate var bindedEvents: [UIButton:EventBinder] = [:]

fileprivate class EventBinder {

    let event: UIControl.Event
    let button: UIButton
    let handler: UIButton.EventHandler
    let selector: Selector

    required init(
        _ event: UIControl.Event,
        on button: UIButton,
        withHandler handler: @escaping UIButton.EventHandler
    ) {
        self.event = event
        self.button = button
        self.handler = handler
        self.selector = #selector(performEvent(on:ofType:))
        button.addTarget(self, action: self.selector, for: event)
    }

    deinit {
        button.removeTarget(self, action: selector, for: event)
        if let index = bindedEvents.index(forKey: button) {
            bindedEvents.remove(at: index)
        }
    }
}

private extension EventBinder {

    @objc func performEvent(on sender: UIButton, ofType event: UIControl.Event) {
        handler(sender, event)
    }
}

extension UIButton {

    typealias EventHandler = (UIButton, UIControl.Event) -> Void

    func on(_ event: UIControl.Event, handler: @escaping EventHandler) {
        bindedEvents[self] = EventBinder(event, on: self, withHandler: handler)
    }
}

Причина, чому я використовував користувальницький клас для прив'язки події, полягає в тому, щоб мати можливість розпоряджатися посиланням пізніше, коли кнопка буде деніціалізована. Це запобіжить можливий витік пам'яті. Це було неможливо в межах UIButtonйого розширення, тому що мені не дозволено реалізувати властивість чи deinitметод.


2

Якщо у вас є петля кнопок, як я, ви можете спробувати щось подібне

var buttonTags:[Int:String]? // can be [Int:Any]
let myArray = [0:"a",1:"b"]
for (index,value) in myArray {

     let button = // Create a button

     buttonTags?[index] = myArray[index]
     button.tag = index
     button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchDown)

}
@objc func buttonAction(_ sender:UIButton) {

    let myString = buttonTags[sender.tag]

}

2

Код Swift 4.0 (Ось ми знову)

Викликана дія повинна бути позначена так, оскільки це синтаксис функції swift для експорту функцій на об'єктивну мову c.

@objc func deleteAction(sender: UIButton) {
}

створити робочу кнопку:

let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Delete", for: [])
deleteButton.addTarget(self, action: #selector( 
MyController.deleteAction(sender:)), for: .touchUpInside)

Дякую, що поділились. Це працює, але позначення його @objc вважає неінтуїтивним. Чи можете ви пояснити міркування цього?
rawbee

@rawbee Погодьтеся, що це контрінтуїтивно. Це питання має більше фону: stackoverflow.com/questions/44390378 / ...
Mikrasya

1

Код Swift 5.0

Я використовую theButton.tag, але якщо у мене є багато варіантів, це дуже довгий вимикач.

theButton.addTarget(self, action: #selector(theFunc), for: .touchUpInside) 
theButton.frame.name = "myParameter"

.

@objc func theFunc(sender:UIButton){ 
print(sender.frame.name)
}

0

Для Swift 2.X і вище

button.addTarget(self,action:#selector(YourControllerName.buttonClicked(_:)),
                         forControlEvents:.TouchUpInside)

0

Код Swift 3.0

self.timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector:#selector(fetchAutocompletePlaces(timer:)), userInfo:[textView.text], repeats: true)

func fetchAutocompletePlaces(timer : Timer) {

  let keyword = timer.userInfo
}

Ви можете надіслати значення у "userinfo" і використовувати це як параметр у функції.


0

Це більше важливий коментар. Спільний доступ до посилань на sytanx, прийнятний поза полем. Щоб отримати рішення щодо злому, подивіться інші відповіді.

За документами Apple, визначення методу дії повинні бути або одним із цих трьох. Все інше не приймається.

@IBAction func doSomething()
@IBAction func doSomething(sender: UIButton)
@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.