[ नोट: यह उत्तर मूल रूप से स्विफ्ट 2.2 के तहत तैयार किया गया था। यह स्विफ्ट 4 के लिए संशोधित किया गया है, जिसमें दो महत्वपूर्ण भाषा परिवर्तन शामिल हैं: पहला विधि पैरामीटर बाहरी अब स्वचालित रूप से दबा हुआ नहीं है, और एक चयनकर्ता को स्पष्ट रूप से ऑब्जेक्टिव-सी के संपर्क में होना चाहिए।]
आप अपने कार्य संदर्भ को सही विधि हस्ताक्षर में डालकर इस समस्या को हल कर सकते हैं :
let selector = #selector(test as () -> Void)
(हालांकि, मेरी राय में, आपको ऐसा नहीं करना चाहिए। मैं इस स्थिति को एक बग के रूप में मानता हूं, यह दर्शाता है कि कार्यों का संदर्भ देने के लिए स्विफ्ट का वाक्यविन्यास अपर्याप्त है। मैंने एक बग रिपोर्ट दर्ज की, लेकिन कोई फायदा नहीं हुआ।)
बस नए #selector
वाक्यविन्यास को संक्षेप में प्रस्तुत करने के लिए :
इस सिंटैक्स का उद्देश्य ऑल-बहुत-सामान्य रनटाइम क्रैश (आमतौर पर "अपरिचित चयनकर्ता") को रोकना है जो चयनकर्ता को शाब्दिक स्ट्रिंग के रूप में आपूर्ति करते समय उत्पन्न हो सकता है। #selector()
एक फ़ंक्शन संदर्भ लेता है , और कंपाइलर जांच करेगा कि फ़ंक्शन वास्तव में मौजूद है और आपके लिए ऑब्जेक्टिव-सी चयनकर्ता के संदर्भ को हल करेगा। इस प्रकार, आप आसानी से कोई गलती नहीं कर सकते।
( संपादित करें: ठीक है, हाँ, आप कर सकते हैं। आप एक पूर्ण लंकहेड हो सकते हैं और लक्ष्य को ऐसे उदाहरण पर सेट कर सकते हैं, जो इसके द्वारा निर्दिष्ट क्रिया संदेश को कार्यान्वित नहीं करता है #selector
। संकलक आपको रोक नहीं पाएगा और आप जैसे दुर्घटनाग्रस्त हो जाएंगे। अच्छे पुराने दिन। आहें ...)
एक फ़ंक्शन संदर्भ तीन में से किसी भी रूप में दिखाई दे सकता है:
फ़ंक्शन का नंगे नाम । यह पर्याप्त है यदि फ़ंक्शन असंदिग्ध है। इस प्रकार, उदाहरण के लिए:
@objc func test(_ sender:AnyObject?) {}
func makeSelector() {
let selector = #selector(test)
}
केवल एक ही test
विधि है, इसलिए यह #selector
इसे संदर्भित करता है भले ही यह एक पैरामीटर लेता है और पैरामीटर का #selector
उल्लेख नहीं करता है। पर्दे के पीछे सुलझा हुआ ऑब्जेक्टिव-सी सिलेक्टर, अभी भी सही ढंग से "test:"
(कोलोन के साथ, एक पैरामीटर को दर्शाता है) होगा।
फ़ंक्शन का नाम इसके बाकी हस्ताक्षर के साथ । उदाहरण के लिए:
func test() {}
func test(_ sender:AnyObject?) {}
func makeSelector() {
let selector = #selector(test(_:))
}
हमारे पास दो test
तरीके हैं, इसलिए हमें अंतर करने की आवश्यकता है; अंकन test(_:)
पर ले कर दूसरे एक, एक पैरामीटर के साथ एक।
अपने शेष हस्ताक्षर के साथ या बिना फ़ंक्शन का नाम, साथ ही मापदंडों के प्रकार को दिखाने के लिए एक कास्ट । इस प्रकार:
@objc func test(_ integer:Int) {}
@nonobjc func test(_ string:String) {}
func makeSelector() {
let selector1 = #selector(test as (Int) -> Void)
let selector2 = #selector(test(_:) as (Int) -> Void)
}
यहां, हमने ओवरलोड किया है test(_:)
। ओवरलोडिंग, ऑब्जेक्टिव-सी के संपर्क में नहीं किया जा सकता क्योंकि ऑब्जेक्टिव-सी अधिक भार की अनुमति नहीं देता है, तो उनमें से केवल एक सामने आ रहा है, और हम केवल यह है कि एक के लिए एक चयनकर्ता फार्म कर सकते हैं है अवगत कराया, क्योंकि चयनकर्ताओं एक ऑब्जेक्टिव-सी विशेषता है । लेकिन हमें अभी भी स्पष्ट होना चाहिए जहां तक स्विफ्ट का संबंध है, और कास्ट ऐसा करता है।
(यह भाषाई विशेषता है जिसका उपयोग किया जाता है - दुरुपयोग, मेरी राय में - ऊपर दिए गए उत्तर के आधार के रूप में)
इसके अलावा, आपको स्विफ्ट को फ़ंक्शन संदर्भ को यह बताने में मदद करनी पड़ सकती है कि फ़ंक्शन किस वर्ग में है:
यदि कक्षा इस एक के समान है, या इस एक से सुपरक्लास श्रृंखला ऊपर है, तो कोई और रिज़ॉल्यूशन आमतौर पर आवश्यक नहीं है (जैसा कि ऊपर के उदाहरणों में दिखाया गया है); वैकल्पिक रूप से, आप कह सकते हैं self
, डॉट-नोटेशन (उदाहरण के लिए #selector(self.test)
, और कुछ स्थितियों में आपको ऐसा करना पड़ सकता है।
अन्यथा, आप या तो एक उदाहरण के लिए संदर्भ का उपयोग करते हैं जिसके लिए विधि को लागू किया जाता है, डॉट-नोटेशन के साथ, जैसा कि इस वास्तविक-जीवन उदाहरण में ( self.mp
एक MPMusicPlayerController है):
let pause = UIBarButtonItem(barButtonSystemItem: .pause,
target: self.mp, action: #selector(self.mp.pause))
... या आप डॉट-नोटेशन के साथ वर्ग के नाम का उपयोग कर सकते हैं :
class ClassA : NSObject {
@objc func test() {}
}
class ClassB {
func makeSelector() {
let selector = #selector(ClassA.test)
}
}
(यह एक जिज्ञासु संकेतन लगता है, क्योंकि ऐसा लगता है कि आप कह रहे हैं कि test
उदाहरण विधि के बजाय एक वर्ग विधि है, लेकिन यह सही ढंग से एक चयनकर्ता को फिर भी हल किया जाएगा, जो कि सभी मामलों में है।)