Lampirkan parameter ke tindakan button.addTarget di Swift

102

Saya mencoba meneruskan parameter tambahan ke tindakan buttonClicked, tetapi tidak dapat mengetahui sintaks apa yang seharusnya ada di Swift.

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

Setiap metode buttonClicked saya:

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

Ada yang punya ide?

Terima kasih atas bantuan Anda.

iphaaw.dll
sumber
1
Lihat tautan ini untuk jawaban terperinci dan praktik terbaik
lembar
Pertanyaan tersebut tidak memiliki jawaban yang baik karena sudah menggambarkan arsitektur yang bermasalah. Anda tidak membutuhkan parameter tambahan. Kebutuhan akan parameter tambahan merupakan masalah dalam arsitektur Anda.
Sulthan
WARNING TO INTERNET: please check out my answer at the bottom
Tuan Heelis

Jawaban:

170

Anda tidak dapat meneruskan parameter khusus di addTarget:. Satu alternatif adalah mengatur tagproperti tombol dan bekerja berdasarkan tag.

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

Atau untuk Swift 2.2 dan yang lebih baru:

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

Sekarang lakukan logika berdasarkan tagproperti

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

        var abc = "argOne" //Do something for tag 5
    }
    print("hello")
}
codester
sumber
4
Hai, Jika saya ingin mendapatkan indexPath atau sel tombol di tableView, apakah mungkin?
NKurapati
1
Berikut petunjuknya: Jangan jadikan metode ini pribadi.
OhadM
2
Sepertinya tipe itu hanya bisa menjadi Int. Tidak ada lagi.
scaryguy
2
bagaimana jika saya ingin melewatkan baris dan bagian bersama-sama?
Yestay Muratov
3
asal tahu saja, meskipun ada 118 suara positif (dan terus bertambah), ini adalah cara yang salah untuk melakukan ini
Tuan Heelis
79

Jika Anda ingin mengirim parameter tambahan ke metode buttonClicked, misalnya indexPath atau urlString, Anda dapat membuat subclass UIButton:

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

Pastikan untuk mengubah kelas tombol di inspektur identitas menjadi subclassedUIButton. Anda dapat mengakses parameter di dalam metode buttonClicked menggunakan sender.indexPathatau sender.urlString.

Catatan: Jika tombol Anda berada di dalam sel, Anda dapat mengatur nilai parameter tambahan ini dalam metode cellForRowAtIndexPath (tempat tombol dibuat).

uclagamer
sumber
5
Ini adalah satu-satunya cara yang berhasil bagi saya. Tapi saya penasaran, apakah ini anti pola atau bukan?
scaryguy
1
Ini adalah cara terbaik, menurut saya
Duy Hoang
29

Saya menghargai semua orang yang mengatakan gunakan tag, tetapi Anda benar-benar perlu memperluas kelas UIButton dan cukup menambahkan objek di sana ..

Tag adalah cara putus asa untuk ini. Perpanjang UIButton seperti ini (di 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)
    }
}

maka panggilan Anda mungkin dipanggil (CATATAN titik dua ":" di 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"

lalu akhirnya tangkap semuanya di sini

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

Anda melakukan ini satu kali dan menggunakannya di seluruh proyek Anda (Anda bahkan dapat membuat kelas anak memiliki "objek" generik dan memasukkan apa pun yang Anda suka ke dalam tombol!). Atau gunakan contoh di atas untuk memasukkan jumlah parameter kunci / string yang tidak ada habisnya ke dalam tombol .. Sangat berguna untuk menyertakan hal-hal seperti url, metodologi konfirmasi pesan, dll.

Selain itu, penting bagi SOkomunitas untuk menyadari bahwa ada seluruh generasi praktik buruk yang dipotong-potong di internet oleh sejumlah programer yang tidak mengerti / belum diajarkan / melewatkan inti dari konsepobject extensions

Tuan Heelis
sumber
10

Untuk Swift 3.0 Anda dapat menggunakan berikut ini

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

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

}
MK_iOS
sumber
9

Swift 4.2.0

Hasil:

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

Di file, UIButton+Events.swiftsaya telah membuat metode ekstensi untuk UIButtonitu mengikat UIControl.Eventke penangan penyelesaian yang disebut 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)
    }
}

Alasan mengapa saya menggunakan kelas khusus untuk mengikat acara adalah untuk dapat membuang referensi nanti ketika tombol dideintialisasi. Ini akan mencegah kemungkinan kebocoran memori terjadi. Ini tidak mungkin dilakukan dalam UIButtonekstensinya, karena saya tidak diizinkan untuk mengimplementasikan properti atau deinitmetode.

Lloyd Keijzer
sumber
2

Jika Anda memiliki lingkaran tombol seperti saya, Anda dapat mencoba sesuatu seperti ini

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]

}
brahimm
sumber
2

Kode Swift 4.0 (Ini dia lagi)

Tindakan yang dipanggil harus ditandai seperti ini karena itu adalah sintaks untuk fungsi swift untuk mengekspor fungsi ke bahasa c tujuan.

@objc func deleteAction(sender: UIButton) {
}

buat beberapa tombol yang berfungsi:

let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Delete", for: [])
deleteButton.addTarget(self, action: #selector( 
MyController.deleteAction(sender:)), for: .touchUpInside)
Karsten
sumber
Terima kasih telah berbagi. Ini berfungsi, tetapi menandainya dengan @objc terasa tidak intuitif. Bisakah Anda menjelaskan alasannya?
rawbee
@rawbee Setuju bahwa ini berlawanan dengan intuisi. Pertanyaan ini memiliki lebih banyak latar belakang: stackoverflow.com/questions/44390378/…
Mikrasya
1

Kode Swift 5.0

Saya menggunakan theButton.tag tetapi jika saya memiliki banyak jenis opsi, ini akan menjadi kasus sakelar yang sangat panjang.

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

.

@objc func theFunc(sender:UIButton){ 
print(sender.frame.name)
}
gorimali.dll
sumber
0

Untuk Swift 2.X dan yang lebih baru

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

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

Anda dapat mengirim nilai di 'userinfo' dan menggunakannya sebagai parameter dalam fungsi.

krish
sumber
0

Ini lebih merupakan komentar penting. Berbagi referensi sytanx yang dapat diterima di luar kotak. Untuk solusi peretasan, lihat jawaban lain.

Menurut dokumen Apple, Definisi Metode Tindakan harus salah satu dari ketiganya. Ada lagi yang tidak diterima.

@IBAction func doSomething()
@IBAction func doSomething(sender: UIButton)
@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)
Madu
sumber