swift - स्विफ्ट में @ चयनकर्ता()?
selector nstimer (14)
मैं Swift
में NSTimer
बनाने की कोशिश कर रहा हूं लेकिन मुझे कुछ परेशानी हो रही है।
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
एक ही कक्षा में एक समारोह है।
मुझे संपादक में एक त्रुटि मिलती है:
'Init' के लिए अधिभार नहीं मिला जो आपूर्ति किए गए तर्क स्वीकार करता है
जब मैं selector: test()
बदलता हूं selector: test()
selector: nil
त्रुटि गायब हो जाती है।
मैंने कोशिश की:
-
selector: test()
-
selector: test
-
selector: Selector(test())
लेकिन कुछ भी काम नहीं करता है और मुझे संदर्भों में कोई समाधान नहीं मिल रहा है।
अगर किसी और के पास एक ही समस्या है तो मेरे पास एनएसटीमर के साथ था, जहां किसी भी अन्य उत्तर ने इस मुद्दे को हल नहीं किया है, यह उल्लेख करना महत्वपूर्ण है कि, यदि आप ऐसी कक्षा का उपयोग कर रहे हैं जो NSObject से विरासत में प्राप्त नहीं होता है या तो पदानुक्रम में सीधे या गहरा होता है ( उदाहरण के लिए मैन्युअल रूप से बनाई गई त्वरित फ़ाइलें), अन्य उत्तरों में से कोई भी निम्नानुसार निर्दिष्ट होने पर भी काम करेगा:
let timer = NSTimer(timeInterval: 1, target: self, selector: "test",
userInfo: nil, repeats: false)
func test () {}
कक्षा को एनएसओब्जेक्ट से प्राप्त करने के अलावा किसी और चीज को बदलने के बिना मैंने "अपरिचित चयनकर्ता" त्रुटि प्राप्त करना बंद कर दिया और मेरे तर्क को अपेक्षित रूप से काम करना बंद कर दिया।
आप नीचे की तरह चयनकर्ता बनाते हैं।
1।
UIBarButtonItem(
title: "Some Title",
style: UIBarButtonItemStyle.Done,
target: self,
action: "flatButtonPressed"
)
2।
flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
ध्यान दें कि @ चयनकर्ता वाक्यविन्यास चला गया है और कॉल करने के तरीके को नाम देने वाली एक सरल स्ट्रिंग के साथ प्रतिस्थापित किया गया है। एक ऐसा क्षेत्र है जहां हम सभी रास्ते में प्राप्त होने वाली शब्दावली से सहमत हो सकते हैं। बेशक, अगर हमने घोषणा की कि फ्लैट बटन नामक एक लक्षित विधि है: हम बेहतर लिखते हैं:
func flatButtonPressed(sender: AnyObject) {
NSLog("flatButtonPressed")
}
टाइमर सेट करें:
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: Selector("flatButtonPressed"),
userInfo: userInfo,
repeats: true)
let mainLoop = NSRunLoop.mainRunLoop() //1
mainLoop.addTimer(timer, forMode: NSDefaultRunLoopMode) //2 this two line is optinal
पूरा होने के लिए, यहां फ्लैट बटन दबाया गया है
func flatButtonPressed(timer: NSTimer) {
}
चूंकि स्विफ्ट 3.0 प्रकाशित किया गया है, इसलिए लक्ष्य लक्ष्य घोषित करने के लिए यह थोड़ा और सूक्ष्म है
class MyCustomView : UIView {
func addTapGestureRecognizer() {
// the "_" is important
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyCustomView.handleTapGesture(_:)))
tapGestureRecognizer.numberOfTapsRequired = 1
addGestureRecognizer(tapGestureRecognizer)
}
// since Swift 3.0 this "_" in the method implementation is very important to
// let the selector understand the targetAction
func handleTapGesture(_ tapGesture : UITapGestureRecognizer) {
if tapGesture.state == .ended {
print("TapGesture detected")
}
}
}
भविष्य के पाठकों के लिए, मैंने पाया कि मुझे एक समस्या का सामना करना पड़ा और एक unrecognised selector sent to instance
त्रुटि में unrecognised selector sent to instance
गया था जो लक्ष्य func
को निजी के रूप में चिह्नित करके किया गया था।
किसी ऑब्जेक्ट द्वारा किसी चयनकर्ता के संदर्भ के साथ func
को सार्वजनिक रूप से दृश्यमान होना चाहिए ।
यदि आप एनएसटीमर से फ़ंक्शन में पैरामीटर पास करना चाहते हैं तो यहां आपका समाधान है:
var somethingToPass = "It worked"
let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "tester:", userInfo: somethingToPass, repeats: false)
func tester(timer: NSTimer)
{
let theStringToPrint = timer.userInfo as String
println(theStringToPrint)
}
चयनकर्ता पाठ में कॉलन शामिल करें (परीक्षक :), और आपका पैरामीटर उपयोगकर्ता इन्फॉर्फ़ में जाता है।
आपके फ़ंक्शन को पैरामीटर के रूप में एनएसटीमर लेना चाहिए। फिर पारित पैरामीटर प्राप्त करने के लिए बस userInfo निकालें।
यह ध्यान देने योग्य हो सकता है कि आप उस नियंत्रण को कैसे सेट करते हैं जो क्रिया मामलों को ट्रिगर करता है।
उदाहरण के लिए, मैंने पाया है कि UIBarButtonItem की स्थापना करते समय, मुझे viewDidLoad के भीतर बटन बनाना था या अन्यथा मुझे एक अपरिचित चयनकर्ता अपवाद मिलेगा।
override func viewDidLoad() {
super.viewDidLoad()
// add button
let addButton = UIBarButtonItem(image: UIImage(named: "746-plus-circle.png"), style: UIBarButtonItemStyle.Plain, target: self, action: Selector("addAction:"))
self.navigationItem.rightBarButtonItem = addButton
}
func addAction(send: AnyObject?) {
NSLog("addAction")
}
स्विफ्ट स्वयं चयनकर्ताओं का उपयोग नहीं करता है - उद्देश्य-सी में कई डिज़ाइन पैटर्न चयनकर्ताओं का उपयोग स्विफ्ट में अलग-अलग काम करते हैं। (उदाहरण के लिए, प्रोटोकॉल प्रकारों पर वैकल्पिक चेनिंग का उपयोग करें या respondsToSelector:
बजाय परीक्षण के as
is
/ performSelector:
और प्रदर्शन के बजाए जहां भी आप कर सकते हैं बंद करें का चयन performSelector:
बेहतर प्रकार / स्मृति सुरक्षा के लिए।)
लेकिन अभी भी कई महत्वपूर्ण ओबीजेसी-आधारित एपीआई हैं जो टाइमर और लक्ष्य / क्रिया पैटर्न समेत चयनकर्ताओं का उपयोग करते हैं। स्विफ्ट इनके साथ काम करने के लिए Selector
प्रकार प्रदान करता है। (स्विफ्ट स्वचालित रूप से ओबीजेसी के SEL
प्रकार के स्थान पर इसका उपयोग करता है।)
स्विफ्ट 2.2 (एक्सकोड 7.3) और बाद में (स्विफ्ट 3 / एक्सकोड 8 और स्विफ्ट 4 / एक्सकोड 9 सहित):
आप # Selector
अभिव्यक्ति का उपयोग कर एक स्विफ्ट फ़ंक्शन प्रकार से Selector
सकते हैं।
let timer = Timer(timeInterval: 1, target: object,
selector: #selector(MyClass.test),
userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
with: button, with: otherButton)
इस दृष्टिकोण के बारे में महान बात? एक फ़ंक्शन संदर्भ स्विफ्ट कंपाइलर द्वारा चेक किया गया है, ताकि आप केवल # वर्ग चयनकर्ता वर्ग / विधि जोड़े के साथ उपयोग कर #selector
जो वास्तव में मौजूद हैं और चयनकर्ताओं के रूप में उपयोग के लिए योग्य हैं (नीचे "चयनकर्ता उपलब्धता" देखें)। फ़ंक्शन-प्रकार नामकरण के लिए स्विफ्ट 2.2+ नियमों के अनुसार, आप केवल अपने कार्य संदर्भ को यथासंभव विशिष्ट बनाने के लिए स्वतंत्र हैं।
(यह वास्तव में @selector()
के @selector()
निर्देश पर एक सुधार है, क्योंकि कंपाइलर -Wundeclared-selector
चेक केवल सत्यापित करता है कि नामित चयनकर्ता मौजूद है। स्विफ्ट फ़ंक्शन संदर्भ आप # चयनकर्ता अस्तित्व, वर्ग में सदस्यता, और प्रकार हस्ताक्षर को पास करते हैं ।)
आपके द्वारा #selector
अभिव्यक्ति को पारित फ़ंक्शन संदर्भों के लिए कुछ अतिरिक्त चेतावनी दी #selector
:
- फ़ंक्शन संदर्भों के लिए उपरोक्त वाक्यविन्यास का उपयोग करके
insertSubview(_:at:)
नाम वाले एकाधिक फ़ंक्शंस को उनके पैरामीटर लेबल द्वारा अलग किया जा सकता है (उदाहरण के लिएinsertSubview(_:at:)
बनामinsertSubview(_:aboveSubview:)
)। लेकिन अगर किसी फ़ंक्शन में कोई पैरामीटर नहीं है, तो इसे असंबद्ध करने का एकमात्र तरीका फ़ंक्शन के प्रकार हस्ताक्षर (जैसेfoo as () -> ()
बनामfoo(_:)
) के साथ कलाकार केas
उपयोग करना है। - स्विफ्ट 3.0+ में संपत्ति गेटर / सेटर जोड़े के लिए एक विशेष वाक्यविन्यास है। उदाहरण के लिए, एक
var foo: Int
दिया गयाvar foo: Int
, आप#selector(getter: MyClass.foo)
#selector(setter: MyClass.foo)
#selector(getter: MyClass.foo)
या#selector(setter: MyClass.foo)
#selector(getter: MyClass.foo)
उपयोग कर सकते हैं।
सामान्य टिप्पणी:
मामले जहां #selector
काम नहीं करता है, और नामकरण: कभी-कभी आपके पास चयनकर्ता बनाने के लिए फ़ंक्शन संदर्भ नहीं होता है (उदाहरण के लिए, ओबीजेसी रनटाइम में गतिशील रूप से पंजीकृत विधियों के साथ)। उस स्थिति में, आप एक स्ट्रिंग से Selector
सकते हैं: उदाहरण के लिए Selector("dynamicMethod:")
- हालांकि आप संकलक की वैधता जांच खो देते हैं। जब आप ऐसा करते हैं, तो आपको प्रत्येक पैरामीटर के लिए कोलन (:) समेत ओबीजेसी नामकरण नियमों का पालन करना होगा।
चयनकर्ता उपलब्धता: चयनकर्ता द्वारा संदर्भित विधि ओबीजेसी रनटाइम के संपर्क में आनी चाहिए। स्विफ्ट 4 में, @objc
संपर्क में आने वाली हर विधि में @objc
विशेषता से पहले इसकी घोषणा होनी चाहिए। (पिछले संस्करणों में आपको कुछ मामलों में यह विशेषता मुफ्त में मिली है, लेकिन अब आपको इसे स्पष्ट रूप से घोषित करना होगा।)
याद रखें कि private
प्रतीक रनटाइम के संपर्क में नहीं आते हैं - आपकी विधि में कम से कम internal
दृश्यता की आवश्यकता होती है।
मुख्य पथ: ये संबंधित हैं लेकिन चयनकर्ताओं के समान नहीं हैं। स्विफ्ट 3 में इनके लिए एक विशेष वाक्यविन्यास भी है: उदाहरण के लिए chris.valueForKeyPath(#keyPath(Person.friends.firstName))
। विवरण के लिए SE-0062 देखें। और स्विफ्ट 4 में और भी KeyPath
सामग्री , इसलिए सुनिश्चित करें कि यदि उपयुक्त हो तो आप चयनकर्ताओं के बजाय सही कीपैथ-आधारित API का उपयोग कर रहे हैं।
आप कोको और उद्देश्य-सी के साथ स्विफ्ट का उपयोग करने में उद्देश्य-सी एपीआई के साथ इंटरैक्टिंग के तहत चयनकर्ताओं के बारे में अधिक पढ़ सकते हैं।
नोट: स्विफ्ट 2.2 से पहले, Selector
StringLiteralConvertible
अनुरूप है, इसलिए आपको पुराना कोड मिल सकता है जहां चयनकर्ताओं को लेने वाले एपीआई को नंगे स्ट्रिंग पास की जाती हैं। #selector
का उपयोग करने वाले लोगों को प्राप्त करने के लिए आप #selector
में "वर्तमान स्विफ्ट सिंटेक्स में कनवर्ट करें" को चलाने के लिए चाहते हैं।
स्विफ्ट पर Selector
वर्ग का उपयोग करने के तरीके पर एक त्वरित उदाहरण दिया गया है:
override func viewDidLoad() {
super.viewDidLoad()
var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
self.navigationItem.rightBarButtonItem = rightButton
}
func method() {
// Something cool here
}
ध्यान दें कि यदि स्ट्रिंग के रूप में पारित विधि काम नहीं करती है, तो यह रनटाइम पर विफल हो जाएगी, समय संकलित नहीं करेगा, और आपके ऐप को क्रैश करेगी। सावधान रहे
# चयनकर्ता का उपयोग करके यह सुनिश्चित करने के लिए संकलित समय पर अपना कोड जांचें कि जिस विधि को आप कॉल करना चाहते हैं वास्तव में मौजूद है। इससे भी बेहतर, यदि विधि मौजूद नहीं है, तो आपको संकलन त्रुटि मिल जाएगी: एक्सकोड आपके ऐप को बनाने से इंकार कर देगा, इस प्रकार बग के एक और संभावित स्रोत को विस्मृत करने के लिए गायब हो जाएगा।
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem =
UIBarButtonItem(barButtonSystemItem: .Add, target: self,
action: #selector(addNewFireflyRefernce))
}
func addNewFireflyReference() {
gratuitousReferences.append("Curse your sudden but inevitable betrayal!")
}
चयनकर्ता वाक्यविन्यास के लिए कॉलिंग विधि में एक सरल स्ट्रिंग नामकरण के रूप में बदलें
var timer1 : NSTimer? = nil
timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)
उसके बाद, func test () टाइप करें।
स्विफ्ट 2.2+ और स्विफ्ट 3 अपडेट
नई #selector
अभिव्यक्ति का उपयोग करें, जो स्ट्रिंग #selector
का उपयोग करने की आवश्यकता को कम त्रुटि-प्रवण बनाने की आवश्यकता को समाप्त करता है। सन्दर्भ के लिए:
Selector("keyboardDidHide:")
हो जाता है
#selector(keyboardDidHide(_:))
यह भी देखें: स्विफ्ट विकास प्रस्ताव
नोट (स्विफ्ट 4.0):
यदि #selector
का उपयोग #selector
तो आपको फ़ंक्शन को @objc
रूप में चिह्नित करने की आवश्यकता होगी
उदाहरण:
@objc func something(_ sender: UIButton)
स्विफ्ट 4.0
आप नीचे की तरह चयनकर्ता बनाते हैं।
1. घटना को एक बटन पर जोड़ें:
button.addTarget(self, action: #selector(clickedButton(sender:)), for: UIControlEvents.touchUpInside)
और समारोह नीचे जैसा होगा:
@objc func clickedButton(sender: AnyObject) {
}
// for swift 2.2
// version 1
buttton.addTarget(self, action: #selector(ViewController.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(ViewController.tappedButton2(_:)), forControlEvents: .TouchUpInside)
// version 2
buttton.addTarget(self, action: #selector(self.tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(self.tappedButton2(_:)), forControlEvents: .TouchUpInside)
// version 3
buttton.addTarget(self, action: #selector(tappedButton), forControlEvents: .TouchUpInside)
buttton.addTarget(self, action: #selector(tappedButton2(_:)), forControlEvents: .TouchUpInside)
func tappedButton() {
print("tapped")
}
func tappedButton2(sender: UIButton) {
print("tapped 2")
}
// swift 3.x
button.addTarget(self, action: #selector(tappedButton(_:)), for: .touchUpInside)
func tappedButton(_ sender: UIButton) {
// tapped
}
button.addTarget(self, action: #selector(tappedButton(_:_:)), for: .touchUpInside)
func tappedButton(_ sender: UIButton, _ event: UIEvent) {
// tapped
}
Create Refresh control using Selector method.
var refreshCntrl : UIRefreshControl!
refreshCntrl = UIRefreshControl()
refreshCntrl.tintColor = UIColor.whiteColor()
refreshCntrl.attributedTitle = NSAttributedString(string: "Please Wait...")
refreshCntrl.addTarget(self, action:"refreshControlValueChanged", forControlEvents: UIControlEvents.ValueChanged)
atableView.addSubview(refreshCntrl)
// ताज़ा नियंत्रण विधि
func refreshControlValueChanged(){
atableView.reloadData()
refreshCntrl.endRefreshing()
}