स्विफ्ट में बटन .addTarget कार्रवाई के लिए पैरामीटर संलग्न करें


102

मैं बटन क्लिक्स्ड एक्शन के लिए एक अतिरिक्त पैरामीटर पास करने की कोशिश कर रहा हूं, लेकिन स्विफ्ट में सिंटैक्स क्या होना चाहिए, यह काम नहीं कर सकता।

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

मेरी कोई भी बटन विधि:

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

किसी को कोई विचार?

आपकी सहायता के लिए धन्यवाद।


1
एक विस्तृत उत्तर और सर्वोत्तम अभ्यास के लिए इस लिंक का संदर्भ लें
शीतल

प्रश्न का अच्छा जवाब नहीं है क्योंकि यह पहले से ही एक समस्याग्रस्त वास्तुकला का वर्णन करता है। आपको एक अतिरिक्त पैरामीटर की आवश्यकता नहीं है। एक अतिरिक्त पैरामीटर की आवश्यकता आपके आर्किटेक्चर में एक समस्या है।
सुल्तान

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)

या स्विफ्ट 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
नमस्ते, अगर मैं tableView में indexPath या बटन की सेल प्राप्त करना चाहता हूं, तो क्या यह संभव है?
NKurapati

1
यहाँ एक संकेत है: विधि को निजी न बनाएं।
ओएचडीएम

2
ऐसा लगता है कि यह केवल एक प्रकार हो सकता है Int। और कुछ नहीं।
scaryguy

2
क्या होगा अगर मैं एक साथ पंक्ति और अनुभाग पास करना चाहता हूं?
यास्ते मुराटोव

3
बस आप जानते हैं, 118 अपवोट्स (और गिनती) के बावजूद ऐसा करने का गलत तरीका है
श्री हीलिस

79

यदि आप बटन पैरामीटर विधि के लिए अतिरिक्त पैरामीटर भेजना चाहते हैं, उदाहरण के लिए एक indexPath या urlString, तो आप UIButton को उपवर्ग कर सकते हैं:

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

आइडेंटिटी इंस्पेक्टर में बटन की क्लास को सबक्लासड यूआईट्यूटन में बदलना सुनिश्चित करें। आप का उपयोग buttonClicked विधि के अंदर मापदंडों का उपयोग कर सकते sender.indexPathया sender.urlString

नोट: यदि आपका बटन किसी कक्ष के अंदर है, तो आप इन अतिरिक्त मापदंडों का मान CellForRowAtIndexPath विधि (जहाँ बटन बनाया गया है) को सेट कर सकते हैं।


5
यह एकमात्र तरीका था जिसने मेरे लिए काम किया। लेकिन मैं जिज्ञासु हूं, क्या यह विरोधी पैटर्न है या नहीं?
scaryguy

1
यह सबसे अच्छा तरीका है, मुझे लगता है
Duy Hoang

29

मैं सभी को टैग का उपयोग करते हुए कह रहा हूँ, लेकिन वास्तव में आपको UIButton वर्ग का विस्तार करने की आवश्यकता है और बस वहाँ की वस्तु को जोड़ना चाहिए ।।

टैग इस तरह से एक निराशाजनक तरीका है। इस तरह UIButton बढ़ाएँ (स्विफ्ट 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)
    }
}

तब आपका कॉल कॉल हो सकता है (नोट कॉलन ":" में 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"] ?? "")
}

आप इसे एक बार करते हैं और अपने पूरे प्रोजेक्ट में इसका उपयोग करते हैं (आप चाइल्ड क्लास को एक सामान्य "ऑब्जेक्ट" भी बना सकते हैं और जो कुछ भी आपको पसंद है उसे बटन में डाल सकते हैं!)। या बटन में कुंजी / स्ट्रिंग परम की एक अटूट संख्या डालने के लिए ऊपर दिए गए उदाहरण का उपयोग करें .. वास्तव में उपयोगी चीजें जैसे कि यूआरएल, पुष्टि संदेश पद्धति आदि के लिए।

एक तरफ के रूप में, यह महत्वपूर्ण है कि SOसमुदाय को यह एहसास हो कि बुरी प्रथा की पूरी पीढ़ी में कटौती की जा रही है। प्रोग्रामर की एक खतरनाक संख्या के आधार पर इंटरनेट को गोल किया जाता है, जो समझ में नहीं आता / सिखाया नहीं गया / याद नहीं किया गया इसकी अवधारणाobject extensions


10

स्विफ्ट 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.EventEventHandler

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

स्विफ्ट 4.0 कोड (यहां हम फिर से जाते हैं)

इस तरह की कार्रवाई को इस तरह चिह्नित किया जाना चाहिए क्योंकि यह उद्देश्य सी भाषा में निर्यात कार्यों के लिए तेजी से कार्य के लिए वाक्यविन्यास है।

@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 के साथ इसे चिह्नित करना अनकहा लगता है। क्या आप इसके लिए तर्क बता सकते हैं?
रॉबी

@ क्रैबी सहमत हैं कि यह प्रतिवाद है। इस प्रश्न की पृष्ठभूमि अधिक है: stackoverflow.com/questions/44390378/…
मिक्रिया

1

स्विफ्ट 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

स्विफ्ट 2.X और उससे अधिक के लिए

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

0

स्विफ्ट 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 Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.