गैर - '@ objc' विधि '@objc' प्रोटोकॉल की वैकल्पिक आवश्यकता को पूरा नहीं करती है


103

अवलोकन:

  • मेरे पास एक प्रोटोकॉल P1 है जो उद्देश्य-सी वैकल्पिक कार्यों में से एक का डिफ़ॉल्ट कार्यान्वयन प्रदान करता है।
  • जब मैं वैकल्पिक फ़ंक्शन का डिफ़ॉल्ट कार्यान्वयन प्रदान करता हूं तो एक चेतावनी होती है

संकलक चेतावनी:

Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'

संस्करण:

  • स्विफ्ट: 3
  • Xcode: 8 (सार्वजनिक रिलीज)

किए गए प्रयास:

  • जोड़ने की कोशिश की, @objcलेकिन मदद नहीं करता है

सवाल:

  • मैंने इसे कैसे हल किया?
  • क्या आसपास कोई काम है ?

कोड:

@objc protocol P1 : UIAdaptivePresentationControllerDelegate {

}

extension P1 where Self : UIViewController {

    func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        return UIViewController()
    }
}


class A : UIViewController, P1 {

}

क्या आपके पास Xcode का नवीनतम संस्करण है? अगर मुझे हटा दिया जाए तो मुझे कोई त्रुटि नहीं मिलती है@objc
Qbyte

मैं Xcode 8 (नवीनतम सार्वजनिक संस्करण) का उपयोग कर रहा हूं। कोई त्रुटि नहीं है, लेकिन एक चेतावनी होगी
user1046037

जवाबों:


182

जबकि मुझे लगता है कि मैं आपके प्रश्न का उत्तर दे सकता हूं, यह ऐसा उत्तर नहीं है जिसे आप पसंद करेंगे।

TL; DR: @objc फ़ंक्शंस वर्तमान में प्रोटोकॉल एक्सटेंशन में नहीं हो सकते हैं। आप इसके बजाय एक आधार वर्ग बना सकते हैं, हालांकि यह एक आदर्श समाधान नहीं है।

प्रोटोकॉल एक्सटेंशन और ऑब्जेक्टिव-सी

सबसे पहले, यह प्रश्न / उत्तर ( ऑब्जेक्टिव-सी में एक्सेस किए गए प्रोटोकॉल पर एक्सटेंशन्स पर परिभाषित स्विफ्ट मेथड डिफाइन हो सकता है ) सुझाव देता है कि जिस तरह से प्रोटोकॉल एक्सटेंशन को हुड के तहत भेजा जाता है, प्रोटोकॉल एक्सटेंशन में घोषित तरीके objc_msgSend()फ़ंक्शन के लिए दिखाई नहीं देते हैं , और इसलिए Objective-C कोड के लिए दृश्यमान नहीं हैं। चूँकि जिस विधि को आप अपने विस्तार में परिभाषित करने की कोशिश कर रहे हैं, उसे ऑब्जेक्टिव-सी (इसलिए UIKitइसका उपयोग कर सकते हैं) के लिए दृश्यमान होना चाहिए , यह आपको शामिल नहीं करने के लिए चिल्लाता है @objc, लेकिन एक बार जब आप इसे शामिल करते हैं, तो यह आपको चिल्लाता है क्योंकि @objcइसमें अनुमति नहीं है प्रोटोकॉल एक्सटेंशन। यह शायद इसलिए है क्योंकि प्रोटोकॉल एक्सटेंशन वर्तमान में ऑब्जेक्टिव-सी के लिए दृश्यमान नहीं हैं।

हम यह भी देख सकते हैं कि त्रुटि संदेश एक बार हम कहते हैं @objcकि "@objc का उपयोग केवल कक्षाओं के सदस्यों, @objc प्रोटोकॉल और कक्षाओं के ठोस एक्सटेंशन के साथ किया जा सकता है।" यह कोई वर्ग नहीं है; एक @objc प्रोटोकॉल का विस्तार प्रोटोकॉल परिभाषा में होने के कारण ही नहीं है (यानी आवश्यकताओं में), और शब्द "कंक्रीट" यह सुझाव देगा कि एक प्रोटोकॉल एक्सटेंशन एक ठोस वर्ग एक्सटेंशन के रूप में नहीं गिना जाता है।

वैकल्पिक हल

दुर्भाग्य से, यह बहुत अधिक पूरी तरह से आपको प्रोटोकॉल एक्सटेंशन का उपयोग करने से रोकता है, जब डिफ़ॉल्ट कार्यान्वयन ऑब्जेक्टिव-सी फ्रेमवर्क को दिखाई देना चाहिए। सबसे पहले, मुझे लगा कि शायद @objcआपके प्रोटोकॉल एक्सटेंशन में अनुमति नहीं थी क्योंकि स्विफ्ट कंपाइलर गारंटी नहीं दे सकता था कि अनुरूप प्रकार वर्ग होंगे (भले ही आपने विशेष रूप से निर्दिष्ट किया हो UIViewController)। इसलिए मैंने एक classआवश्यकता रखी P1। यह काम नहीं किया।

शायद केवल वर्कअराउंड यहां प्रोटोकॉल के बजाय बस बेस क्लास का उपयोग करना है, लेकिन यह स्पष्ट रूप से पूरी तरह से आदर्श नहीं है क्योंकि एक वर्ग में केवल एक ही आधार वर्ग हो सकता है लेकिन कई प्रोटोकॉल के अनुरूप है।

यदि आप इस मार्ग पर जाने का विकल्प चुनते हैं, तो कृपया इस प्रश्न ( स्विफ्ट 3 ओबीजीसी ऑप्शनल प्रोटोकॉल मेथड नॉट कॉल इन सबक्लास ) को ध्यान में रखें। ऐसा प्रतीत होता है कि स्विफ्ट 3 में एक और मौजूदा मुद्दा यह है कि उप-वर्ग अपने सुपरक्लास के वैकल्पिक प्रोटोकॉल आवश्यकता कार्यान्वयन को स्वचालित रूप से विरासत में नहीं लेते हैं। उस प्रश्न का उत्तर @objcइसके चारों ओर प्राप्त करने के लिए एक विशेष अनुकूलन का उपयोग करता है।

समस्या की रिपोर्ट करना

मुझे लगता है कि स्विफ्ट के ओपन सोर्स प्रोजेक्ट्स पर काम करने वालों के बीच इस पर पहले से ही चर्चा हो रही है, लेकिन आप यह सुनिश्चित कर सकते हैं कि वे ऐप्पल के बग रिपोर्टर द्वारा या तो जानते हैं , जो संभवत: स्विफ्ट कोर टीम, या स्विफ्ट के बग रिपोर्टर के लिए अपना रास्ता बनाएंगे । हालाँकि, इनमें से कोई भी आपके बग को बहुत व्यापक या पहले से ज्ञात हो सकता है। स्विफ्ट टीम इस बात पर भी विचार कर सकती है कि आप एक नई भाषा सुविधा के लिए क्या देख रहे हैं, इस मामले में आपको पहले मेलिंग सूचियों की जांच करनी चाहिए ।

अपडेट करें

दिसंबर 2016 में, यह मुद्दा स्विफ्ट समुदाय को बताया गया था । इस मुद्दे को अभी भी एक मध्यम प्राथमिकता के साथ खुला के रूप में चिह्नित किया गया है, लेकिन निम्नलिखित टिप्पणी को जोड़ा गया था:

यह इरादा है। प्रत्येक एडॉप्टर में विधि के कार्यान्वयन को जोड़ने का कोई तरीका नहीं है, क्योंकि प्रोटोकॉल के अनुरूप होने के बाद एक्सटेंशन को जोड़ा जा सकता है। मुझे लगता है कि हम इसे अनुमति दे सकते हैं यदि विस्तार प्रोटोकॉल के समान मॉड्यूल में है, हालांकि।

चूंकि आपका प्रोटोकॉल आपके विस्तार के समान मॉड्यूल में है, हालांकि, आप स्विफ्ट के भविष्य के संस्करण में ऐसा करने में सक्षम हो सकते हैं।

अपडेट २

फरवरी 2017 में, इस मुद्दे को स्विफ्ट कोर टीम के सदस्यों में से एक ने निम्नलिखित संदेश के साथ आधिकारिक तौर पर "डॉन्ट डू" के रूप में बंद कर दिया था :

यह जानबूझकर है: उद्देश्य-सी क्रम की सीमाओं के कारण प्रोटोकॉल एक्सटेंशन @objc प्रविष्टि बिंदुओं को प्रस्तुत नहीं कर सकते हैं। यदि आप NSObject में @objc प्रविष्टि बिंदु जोड़ना चाहते हैं, तो NSObject का विस्तार करें।

विस्तार NSObjectया यहां तक ​​कि UIViewControllerवास्तव में आप क्या चाहते हैं पूरा नहीं होगा, लेकिन यह दुर्भाग्य से ऐसा नहीं लगता है कि यह संभव हो जाएगा।

बहुत (बहुत लंबे समय तक) भविष्य में, हम @objcपूरी तरह से तरीकों पर निर्भरता को समाप्त करने में सक्षम हो सकते हैं , लेकिन वह समय जल्द ही कभी भी नहीं आएगा क्योंकि कोको फ्रेमवर्क वर्तमान में स्विफ्ट में नहीं लिखे गए हैं (और जब तक यह एक स्थिर एबीआई नहीं हो सकता है) ।

अपडेट ३

2019 के पतन के रूप में, यह एक समस्या से कम हो रहा है क्योंकि स्विफ्ट में अधिक से अधिक Apple रूपरेखाएं लिखी जा रही हैं। उदाहरण के लिए, यदि आप SwiftUIइसके बजाय का उपयोग करते हैं UIKit, तो आप समस्या को पूरी तरह से रोक देते हैं क्योंकि @objcकिसी SwiftUIविधि का संदर्भ देते समय यह आवश्यक नहीं होगा ।

स्विफ्ट में लिखे गए Apple फ्रेमवर्क में शामिल हैं:

  • SwiftUI
  • RealityKit
  • जोड़ना
  • CryptoKit

एक को उम्मीद है कि इस पैटर्न को अब समय के साथ जारी रखा जाएगा कि स्विफ्ट आधिकारिक तौर पर एबीआई और मॉड्यूल क्रमशः स्विफ्ट 5.0 और 5.1 के रूप में स्थिर है।


1
@ user1046037 मैं भी यही करता हूं, क्योंकि मैं भविष्य के विकास में कई बार खुद को इस मुद्दे पर चलता हुआ देख सकता हूं।
मैथ्यू सीमैन

2
आप सही हैं, आपका उत्तर अभी भी Swift 4किसी अन्य विकल्प के बावजूद अच्छा है ।
user1046037

1
मेरे पास एक ही कोड था जो मेरे लिए थोड़ी देर के लिए काम कर रहा था लेकिन बाद में Xcode की रिलीज में टूट गया। यह बहुत अचूक है। Objective-C प्रोटोकॉल में बहुत सारे वैकल्पिक तरीके हैं।
डिपार्टमेन्ट बी

0

मैं सिर्फ एक मॉड्यूल के रूप में 'मॉड्यूल स्थिरता' ('वितरण के लिए निर्माण पुस्तकालयों को चालू करने' को सक्षम करने के बाद) में उपयोग किया गया था।

मेरे पास ऐसा कुछ था:

class AwesomeClass: LessAwesomeClass {
...
}

extension AwesomeClass: GreatDelegate {
  func niceDelegateFunc() {
  }
}

एक्सटेंशन में फ़ंक्शन में ये त्रुटियां थीं:

  • 'लेज़अवेक्लेसक्लास' के उपवर्ग के विस्तार में '@objc' इंस्टेंस विधि के लिए iOS 13.0.0 की आवश्यकता होती है

  • गैर - '@ objc' विधि 'niceDelegateFunc' '@objc' प्रोटोकॉल 'GreatDelegate' की आवश्यकता को पूरा नहीं करती है

विस्तार के बजाय कक्षा में कार्यों को स्थानांतरित करने से समस्या हल हो गई।


0

यहाँ एक और समाधान है। मैं इस मुद्दे में भी भाग गया, और अभी तक UIKit से स्विफ्टयूआई पर स्विच नहीं कर सकता। डिफ़ॉल्ट कार्यान्वयन को एक सामान्य आधार वर्ग में ले जाना मेरे लिए कोई विकल्प नहीं था। मेरे डिफ़ॉल्ट कार्यान्वयन काफी व्यापक थे इसलिए मैं वास्तव में उस सभी कोड को डुप्लिकेट नहीं करना चाहता था। मैंने जिस वर्कअराउंड का उपयोग किया था, वह प्रोटोकॉल में आवरण कार्यों का उपयोग करने के लिए था, और फिर बस प्रत्येक वर्ग से उन कार्यों को कॉल करें। सुंदर नहीं है, लेकिन स्थिति के आधार पर विकल्प से बेहतर हो सकता है। आपका कोड तब कुछ इस तरह दिखाई देगा:

@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}

extension P1 where Self : UIViewController {
    func wrapPresentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        return UIViewController()
    }
}

class A : UIViewController, P1 {
    func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        return wrapPresentationController(controller, viewControllerForAdaptivePresentationStyle: style)
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.