Swift'de button.addTarget eylemine parametre ekleyin


104

ButtonClicked eylemine fazladan bir parametre iletmeye çalışıyorum, ancak Swift'de sözdiziminin ne olması gerektiğini hesaplayamıyorum.

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

Herhangi bir buttonClicked yöntemi:

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

Herhangi bir fikri olan var mı?

Yardımınız için teşekkürler.


1
Ayrıntılı bir yanıt ve en iyi uygulama için bu bağlantıya bakın
2016 tarihli sayfa

Sorunun iyi bir cevabı yok çünkü zaten sorunlu bir mimariyi tanımlıyor. Fazladan bir parametreye ihtiyacınız yok. Ek bir parametreye duyulan ihtiyaç, mimarinizde bir sorundur.
Sulthan

WARNING TO INTERNET: please check out my answer at the bottom
Mr Heelis

Yanıtlar:


170

Özel parametreleri içinde geçiremezsiniz. addTarget:Bir alternatif, tagdüğmenin özelliğini ayarlamak ve etikete göre çalışmaktır.

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

Veya Swift 2.2 ve üstü için :

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

Şimdi tagmülke dayalı mantık yapın

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

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

4
Merhaba, tableView'da indexPath veya düğme hücresini almak istersem, bu mümkün mü?
NKurapati

1
İşte bir ipucu: Yöntemi özel yapmayın.
OhadM

2
Görünüşe göre türü yalnızca bir Int. Başka hiçbir şey.
scaryguy

2
Ya satır ve bölümü birlikte geçmek istersem?
Yestay Muratov

3
118 olumlu oy (ve saymaya) rağmen bunu yapmanın yanlış yolu bu
Bay Heelis

79

ButtonClicked yöntemine, örneğin bir indexPath veya urlString gibi ek parametreler göndermek istiyorsanız, UIButton'u alt sınıflara ayırabilirsiniz:

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

Kimlik denetçisindeki düğmenin sınıfını alt sınıflıUIButton olarak değiştirdiğinizden emin olun. ButtonClicked yöntemi içindeki parametrelere sender.indexPathveya kullanarak erişebilirsiniz sender.urlString.

Not: Düğmeniz bir hücrenin içindeyse, cellForRowAtIndexPath yönteminde (düğmenin oluşturulduğu yer) bu ek parametrelerin değerini ayarlayabilirsiniz.


5
Benim için işe yarayan tek yol buydu. Ama merak ediyorum, bu anti-model mi değil mi?
scaryguy

1
Bence bu en iyi yol
Duy Hoang

29

Herkesin etiketleri kullan demesini takdir ediyorum, ancak gerçekten UIButton sınıfını genişletmeniz ve nesneyi oraya eklemeniz gerekiyor ..

Etiketler bu konuda umutsuz bir yoldur. UIB düğmesini bu şekilde uzatın (Swift 4'te)

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

aramanız çağrı olabilir (iki nokta üst üste ":" de NOT 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"

sonra sonunda hepsini burada yakalayın

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

Bunu bir kez yaparsınız ve projeniz boyunca kullanırsınız (alt sınıfın genel bir "nesnesine" sahip olmasını bile sağlayabilir ve istediğinizi butona koyabilirsiniz!). Veya düğmeye tükenmez sayıda anahtar / dize parametresi eklemek için yukarıdaki örneği kullanın. URL'ler, mesaj metodolojisini onaylama vb. Gibi şeyleri dahil etmek için gerçekten kullanışlıdır.

Bir kenara, SOtopluluğun, anlamayan / öğretilmemiş / ana fikri kaçıran endişe verici sayıda programcı tarafından internette kesilip yapıştırılan koca bir nesil kötü uygulama olduğunu fark etmesi önemlidir . kavramıobject extensions


10

Swift 3.0 için aşağıdakileri kullanabilirsiniz

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

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

}

9

Swift 4.2

Sonuç:

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

Dosyada UIButton+Events.swift, UIButtonbunun için a'yı UIControl.Eventbir tamamlama işleyicisine bağlayan bir uzantı yöntemi oluşturdum 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)
    }
}

Olayı bağlamak için özel bir sınıf kullanmamın nedeni, referansı daha sonra düğme yeniden başlatıldığında elden çıkarabilmekti. Bu, olası bir bellek sızıntısının oluşmasını önleyecektir. Bu, UIButtonuzantısında mümkün değildi , çünkü bir özelliği veya deinityöntemi uygulamama iznim yok .


2

Benim gibi bir düğme döngüsün varsa, bunun gibi bir şey deneyebilirsin

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 kodu (İşte yine başlıyoruz)

Çağrılan eylem bu şekilde işaretlenmelidir çünkü bu, işlevleri hedef c diline dışa aktarmak için swift işlevinin sözdizimidir.

@objc func deleteAction(sender: UIButton) {
}

biraz çalışma düğmesi oluşturun:

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

Paylaşım için teşekkürler. Bu işe yarıyor, ancak onu @objc ile işaretlemek mantıksız geliyor. Bunun nedenini açıklayabilir misin?
rawbee

@rawbee Bunun mantığa aykırı olduğunu kabul edin. Bu sorunun daha fazla arka planı var: stackoverflow.com/questions/44390378/…
Mikrasya

1

Swift 5.0 kodu

TheButton.tag kullanıyorum, ancak çok sayıda seçeneğim varsa, anahtar durumu çok uzun olabilir.

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 ve üzeri için

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

0

Swift 3.0 kodu

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'da değer gönderebilir ve bunu işlevde parametre olarak kullanabilirsiniz.


0

Bu daha önemli bir yorumdur. Kutudan çıkar çıkmaz kabul edilebilir sytanx referanslarını paylaşmak. Hack çözümleri için diğer cevaplara bakın.

Apple'ın belgelerine göre, Eylem Yöntemi Tanımları bu üçünden biri olmalıdır. Başka hiçbir şey kabul edilmez.

@IBAction func doSomething()
@IBAction func doSomething(sender: UIButton)
@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.