कंपाइलर एरर: ऑब्जेक्टिव-सी सेलेक्टर वाला तरीका पिछले ऑब्जेक्टिव के साथ एक ही ऑब्जेक्टिव-सी सिलेक्टर के साथ टकराव करता है


209

मैं स्विफ्ट सीखना शुरू कर रहा हूं, और YouTube पर बहुत अच्छे स्टैनफोर्ड यूनिवर्सिटी वीडियो व्याख्यान का पालन कर रहा हूं। यहाँ एक लिंक है अगर आप रुचि रखते हैं या यह मदद करता है (हालांकि यह मेरी समस्या को समझने के लिए आवश्यक नहीं है):

IOS 8 ऐप्स को स्विफ्ट के साथ विकसित करना - 2. अधिक Xcode और Swift, MVC

व्याख्यान के बाद मुझे एक बिंदु मिला जहां (जहां तक ​​मैं बता सकता था) मेरा कोड वीडियो में कोड के समान था लेकिन मेरे सिस्टम पर मुझे एक कंपाइलर त्रुटि मिली। बहुत परीक्षण और त्रुटि के बाद मैंने अपने कोड को दो उदाहरणों में कम करने में कामयाबी हासिल की है, जिनमें से एक त्रुटि उत्पन्न करता है, दूसरा या जो नहीं करता है, लेकिन मुझे नहीं पता कि वास्तव में त्रुटि का कारण क्या है या इसे कैसे हल किया जाए।

त्रुटि पैदा करने वाला कोड है:

import UIKit

class BugViewController: UIViewController
{
    func perform(operation: (Double) -> Double) {
    }

    func perform(operation: (Double, Double) -> Double) {
    }
}

यह निम्नलिखित संकलक त्रुटि बनाता है:

उद्देश्य-सी चयनकर्ता के साथ विधि 'प्रदर्शन' प्रदर्शन: 'एक ही उद्देश्य-सी चयनकर्ता के साथ पिछले घोषणा के साथ संघर्ष

बस कोड संकलन UIViewController के उप-क्लासिंग को हटाकर:

import UIKit

class BugViewController
{
    func perform(operation: (Double) -> Double) {
    }

    func perform(operation: (Double, Double) -> Double) {
    }
}

कुछ अन्य जानकारी जो प्रासंगिक हो सकती है या नहीं भी हो सकती है:

  • मैंने हाल ही में योसेमाइट में अपग्रेड किया है।
  • जब मैंने Xcode स्थापित किया, तो मैं एक बीटा संस्करण (संस्करण 6.3 (6D543q)) के साथ समाप्त हो गया क्योंकि (अगर मुझे सही याद है) यह वह संस्करण था जिसे मुझे ओएस एक्स के मेरे संस्करण पर चलाने की आवश्यकता थी।

मैं उम्मीद कर रहा हूं कि यह कंपाइलर में एक बग है क्योंकि अन्यथा इससे मुझे कोई मतलब नहीं है। कोई मदद बहुत आभार प्राप्त!


3
आप Yosemite पर Xcode 6.2 चला सकते हैं। आप इसे ऐप स्टोर से डाउनलोड कर सकते हैं और यह बीटा संस्करण के साथ आपके सिस्टम पर रह सकता है। मैं इस बिंदु पर स्टैनफोर्ड वर्ग के लिए Xcode 6.3 का उपयोग करने की अनुशंसा नहीं करूंगा क्योंकि इसमें बीटा 1.2 और स्विफ्ट 1.2 शामिल है जो अलग है कि वीडियो में उपयोग किए गए स्विफ्ट का पूर्व संस्करण।
वकमा

2
5 अप्रैल से उपयोगकर्ता (फ़ेब) का उत्तर (वर्तमान में स्वीकृत) अब सबसे अच्छा नहीं है। इसके बजाय 16 अप्रैल से (जेम्स झांग) का उत्तर अधिक विशिष्ट और सही है।
फोलेबोटिनम

जवाबों:


144

ऑब्जेक्टिव-सी ओवरलोडिंग विधि का समर्थन नहीं करता है, आपको एक अलग विधि नाम का उपयोग करना होगा। जब आपको UIViewController विरासत में मिली तो आपको NSObject विरासत में मिला और कक्षा को ओब्ज-सी के लिए इंटरोपेबल बनाया। दूसरी ओर स्विफ्ट ओवरलोडिंग का समर्थन करता है, इसीलिए जब आप इनहेरिटेंस हटाते हैं तो यह काम करता है।


2
ऑब्जेक्टिव-सी सपोर्टर्स मेथड ओवरराइडिंग (दमन करने योग्य) कंपाइलर चेतावनियों के साथ (पहले से लागू कुछ ओवरलोडिंग के बारे में आपको सूचित करते हुए), ऐप्पल सिर्फ इतना नहीं चाहता कि आप उनके फ्रेमवर्क को ओवरलोड होने से दूर रखें। मैं UIFontहर दिन ऐसे ओवरलोड फ् का उपयोग कर रहा हूं ।
Michi

@ नीचे पोलरवार का जवाब स्विफ्ट 2 के लिए सबसे अच्छा है: stackoverflow.com/a/31500740/144088
क्रैशलॉट

237

मैं खुद भी स्टैंडफोर्ड कोर्स कर रहा हूं और मैं यहां लंबे समय से अटका हुआ हूं, लेकिन कुछ खोज के बाद, मुझे यहां से कुछ मिला: Xcode के नोट्स जारी किए और इसमें कुछ नीचे दिए गए हैं:

स्विफ्ट 1.2 @objc विधियों और इनिशियलाइज़र के प्रकार-आधारित अधिभार की जाँच करने के बारे में सख्त है, कुछ उद्देश्य-सी द्वारा समर्थित नहीं है।

// Has the Objective-C selector "performOperation:".
func performOperation(op: NSOperation) { /* do something */ }
// Also has the selector "performOperation:".
func performOperation(fn: () -> Void) {
    self.performOperation(NSBlockOperation(block: fn))
}

स्विफ्ट से मंगवाए जाने पर यह कोड काम करेगा, लेकिन अगर ऑब्जेक्टिव-सी से इनवोक किया जाए तो आसानी से क्रैश हो सकता है। इस समस्या को हल करने के लिए, एक प्रकार का उपयोग करें, जो ऑब्जेक्ट-सी रनटाइम के लिए सदस्य को उजागर करने से स्विफ्ट कंपाइलर को रोकने के लिए ऑब्जेक्टिव-सी द्वारा समर्थित नहीं है:

  • यदि यह समझ में आता है, तो @objc की निष्क्रियता को अक्षम करने के लिए सदस्य को निजी के रूप में चिह्नित करें।
  • अन्यथा, डिफ़ॉल्ट मान के साथ डमी पैरामीटर का उपयोग करें, उदाहरण के लिए: _ nonobjc: () = ()। (19826275)

निजी उपवर्गों में ऑब्जेक्टिव-सी के सामने आने वाले तरीकों के ओवरराइड @objc होने का अनुमान नहीं लगाया जाता है, जिससे स्विफ्ट कंपाइलर क्रैश हो जाता है। स्पष्ट रूप से इस तरह के ओवरराइडिंग तरीकों में @objc विशेषता जोड़ें। (19935352)

किसी प्रोजेक्ट या कार्यक्षेत्र में तेज़ी से ओपन का उपयोग करते समय एसडीके से प्रतीक उपलब्ध नहीं होते हैं जो स्विफ्ट का उपयोग करते हैं। (20349540)

मैंने जो किया वह इस तरह ओवरराइड विधि के सामने सिर्फ "निजी" जोड़ना था:

    private func performOperation(operation: Double -> Double) {
    if operandStack.count >= 1 {
        displayValue = operation(operandStack.removeLast())
        enter()
    }
}

3
यह समाधान सबसे अधिक व्यवहार्य है जो मुझे
इम्हो

38
कृपया ध्यान दें कि अब एक @nonobjc विशेषता भी है, जिसका उपयोग ऑब्जेक्टिव-सी रनटाइम से एक विधि को बाहर करने के लिए किया जा सकता है।
एरिक जे

2
मैं दूसरा @ एरिकजे की टिप्पणी और नीचे पोलरवार का जवाब। यह स्विफ्ट 2 और एक्सकोड 7 के साथ आगे बढ़ने का सबसे अच्छा जवाब प्रतीत होता है। 7. यदि आपने अभी तक अपडेट नहीं किया है, तो मैं दृढ़ता से इसकी सिफारिश करता हूं।
ऑस्टिन ए

@ नीचे पोलरवार का जवाब स्विफ्ट 2 के लिए सबसे अच्छा है: stackoverflow.com/a/31500740/144088
Crashalot

111

जैसा कि यह पहले ही उत्तर दिया जा चुका है, ओबजैक विधि ओवरलोडिंग (एक ही नाम के दो तरीके) का समर्थन नहीं करता है और Xcode 7 के तहत स्विफ्ट 2 में इस तरह की समस्याओं को हल करने के लिए दो विकल्प हैं। एक विकल्प विशेषता का उपयोग करके विधि का नाम बदलना है:@objc(newNameMethod:)

func methodOne(par1, par2) {...}

@objc(methodTwo:)
func methodOne(par1) {...}

Xcode 7+ में इस समस्या को हल करने के लिए एक अन्य विकल्प @nonobjcकिसी भी विधि, सबस्क्रिप्ट या इनिशलाइज़र पर विशेषता लागू करने से है

func methodOne() {...}

@nonobjc
func methodOne() {...}

6
यह स्विफ्ट 2 (और ऊपर) के लिए समस्या को हल करता है। सबसे सही उत्तर के रूप में अद्यतन किया जाना चाहिए। Ty।
मैक्सिम वीक्स्लर

2
स्विफ्ट 2 और एक्सकोड 7 + का उपयोग करने वाले किसी भी व्यक्ति के लिए यह सही उत्तर है जो मैं ध्रुवीय के साथ सहमत हूं
TerNovi

17

समस्या UIViewControllerएक @objcवर्ग है। जब से विरासत में मिला है UIViewController, BugViewControllerयह भी एक @objcवर्ग है।

इसका अर्थ यह है कि यह उद्देश्य-सी चयनकर्ताओं (एक विधि का नाम) के नियमों के अनुरूप होना चाहिए। विधियों func perform(operation: (Double) -> Double)और func perform(operation: (Double, Double) -> Double)दोनों का चयनकर्ता एक ही है @selector(perform:)। इसकी अनुमति नहीं है।

इसे हल करने के लिए, विभिन्न नामों का उपयोग करें: जैसे func perform1(operation: (Double) -> Double)और func perform2(operation: (Double, Double) -> Double)


मुझे लगता है कि इसे संभालने का सबसे अच्छा तरीका आपके perform()तरीकों को अधिक वर्णनात्मक नाम देना है। ये तरीके क्या करते हैं? वे दृश्य नियंत्रक की स्थिति कैसे बदलते हैं? UIViewControllerविधि के नामकरण की शैली के लिए एक महसूस करने के लिए अन्य तरीकों को देखें, या एक कक्षा के भीतर विधि के नाम स्पष्ट और अद्वितीय होने चाहिए


धन्यवाद - यह मेरे सवाल का पूरी तरह से जवाब देता है और जैसा कि आप पहले थे मैं इसे सही के रूप में चिह्नित करूंगा।
शुभ अंक

यह कहने के बाद कि मुझे अभी भी समझ में नहीं आया है कि व्याख्यान पर कोड ने काम क्यों किया क्योंकि मुझे पूरा यकीन है कि उसने वही किया जो मेरे गैर-संकलन कोड ने किया था! हे हो - मैं वापस जाऊंगा और इसकी दोहरी जांच करूंगा। कुछ अलग होना चाहिए।
शुभ अंक

2
@ एसेसिस यह एक्सकोड के संस्करण के साथ त्रुटियों का उत्पादन नहीं हो सकता है जो वे वीडियो के लिए उपयोग कर रहे थे लेकिन यह अभी भी एक मुद्दा था। यह Xcode 6.3 तक नहीं था कि संकलक आपको यह चेतावनी देने में सक्षम था।
मिक मैक्लम

3
पॉल हेगार्टी यहां 'ओवरलोडिंग' फ़ंक्शन का प्रदर्शन करना चाहते हैं (एक ही नाम के साथ 2 कार्य, लेकिन तर्कों के अलग-अलग सेट), इसलिए वह उद्देश्य पर समान विधि नाम का उपयोग करते हैं! ओवरलोडिंग की अनुमति केवल स्विफ्ट में है, न कि ऑब्जेक्टिव-सी में। यही कारण है कि समाधान या तो वंशानुक्रम प्रपत्र UIViewController (जो एक उद्देश्य-सी वर्ग है) को हटाने के लिए है, या विधि को निजी घोषित करें। दोनों समाधानों को यहां अन्य उत्तरों में विस्तार से बताया गया है।
रॉनी वेयर्स

वास्तव में मैंने फ़ंक्शन के निजी कीवर्ड का उपयोग किया है। जैसे, प्राइवेट फंक परफॉर्मेशन (ऑपरेशन: डबल -> डबल) {} और प्राइवेट फंक परफॉर्मेशन (ऑपरेशन: (डबल, डबल) -> डबल) {} यहां मैंने प्राइवेट की मदद से ओवरलोडिंग का तरीका हासिल किया। क्योंकि मैं ViewController में दोनों का इस्तेमाल किया। केवल लिफ्ट। कंपाइलर कोई त्रुटि क्यों नहीं कहता है?
iTag

5

"Xcode 6.3 रिलीज़ नोट्स" के तहत https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html से - "स्विफ्ट लैंग्वेज चेंजेज" - आप पाते हैं

स्विफ्ट अब स्विफ्ट प्रकार प्रणाली में ओवरलोडिंग और ओवरराइडिंग और ऑब्जेक्टिव-सी रनटाइम के माध्यम से देखे जाने वाले प्रभावी व्यवहार के बीच विसंगतियों का पता लगाता है।


2

एक ही Obj-C हस्ताक्षर के साथ दो विधियाँ होने के कारण मुझे वही त्रुटि मिली:

static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool
static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool

मैं रनटाइम पर अप्रत्याशित परिणामों की संभावना के कारण उनमें से एक को @nonobjc के रूप में चिह्नित नहीं करना चाहता था। (अगर कोई संभावना नहीं है तो कोई मुझे सही कर सकता है)

स्विफ्ट के बाहरी पैरामीटर नाम सुविधा (मैंने स्थानीय नाम के समान बाहरी नाम) को दूसरी विधि का उपयोग करके इसे हल किया, जो ओबज-सी विधि हस्ताक्षर को प्रभावी ढंग से बदल देता है:

static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.