2015-04-14 25 views
8

में इनिट विधि के भीतर तर्क के रूप में स्वयं को पास करें निम्नलिखित श्रेणी में 'let' संपत्ति को स्पष्ट रूप से अनचाहे चर के रूप में घोषित किया गया है। यह पहले से Xcode 6.2 के साथ काम किया: Xcode 6.3 के लिए अद्यतन करने के बादस्विफ्ट 1.2

class SubView: UIView { 

    let pandGestureRecognizer: UIPanGestureRecognizer! 

    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     self.pandGestureRecognizer = UIPanGestureRecognizer(target: self, action: "panAction:") 
    } 

    func panAction(gesture: UIPanGestureRecognizer) { 
     // ... 
    } 
} 

(स्विफ्ट 1.2 के साथ), निम्नलिखित संकलन त्रुटियां होती हैं:

Property 'self.panGestureRecognizer' not initialized at super.init call 
Immutable value 'self.panGestureRecognizer' may only be initialized once 

super.init कॉल करने से पहले निम्न पंक्ति में ले जाने:

'self' is used before super.init call 
:
self.pandGestureRecognizer = UIPanGestureRecognizer(target: self, action: "panAction:") 

निम्न त्रुटि देता है

संपत्ति 'panGestureRecognizer' को कोई उत्परिवर्तन की आवश्यकता नहीं है, इसलिए इसे निरंतर let 'घोषित किया जाना है। चूंकि यह स्थिर है, इसलिए इसे घोषणा पर प्रारंभिक मूल्य होना चाहिए, या init विधि के भीतर इसे प्रारंभ करना होगा। इसे आरंभ करने के लिए, इसे 'target' पैरामीटर में 'self' पास करना होगा।

अन्य धागे ने इसे स्पष्ट रूप से अनचाहे वैकल्पिक घोषित करने का सुझाव दिया, और इसे super.init कॉल के बाद शुरू किया। यह पहले तक काम करता था जब तक कि मैंने एक्सकोड 6.3 में अपडेट नहीं किया।

क्या कोई इस मामले के लिए उचित कार्यान्वयन या कामकाज जानता है?

+1

यह भाषा के क्रियान्वयन, या यहां तक ​​कि एक विनिर्देशन में एक बग की तरह दिखता है। ऐप्पल के साथ एक बग रिपोर्ट दर्ज करना एक अच्छा विचार है। दुर्भाग्यवश, जब आप अपेक्षाकृत जटिल होते हैं तो एक नई प्रोग्रामिंग भाषा के बीटा-परीक्षण के लिए साइन अप करते समय आपको यही मिलता है। – dasblinkenlight

+0

इसे निरंतर जाने के रूप में घोषित नहीं किया जाना चाहिए। वास्तव में, यदि आप इसे अपनी फ़ाइल के शीर्ष पर वैकल्पिक रूप से घोषित करने जा रहे हैं, तो आपको इसे var के रूप में घोषित करने की आवश्यकता है ताकि आप इसे init विधि में तुरंत चालू कर सकें। – rdelmar

+0

@rdelmar आप घोषित करने की घोषणा कर सकते हैं यह सिर्फ यह लागू करता है कि वे super.init से पहले instatiated हैं। – Fogmeister

उत्तर

12

समस्या

समस्या का let अपने इस्तेमाल होता है - optionals let के रूप में घोषित nil का डिफ़ॉल्ट मान नहीं दिया जाता है (var तथापि है)।

let myOptional: Int? 

if myCondition { 
    myOptional = 1 
} else { 
    myOptional = nil 
} 

इसलिए, आप त्रुटि 'संपत्ति' स्वयं हो रही है: निम्न, स्विफ्ट 1.2 में पेश किया, अन्यथा मान्य के बाद आप इसे घोषित करने के बाद myOptional एक मूल्य देने के लिए सक्षम नहीं होगा नहीं होगा। PanGestureRecognizer 'super.init कॉल पर प्रारंभ नहीं किया गया' क्योंकि super.init(coder: aDecoder) पर कॉल करने से पहले, क्योंकि panGestureRecognizernil नहीं है; इसे बिल्कुल शुरू नहीं किया गया है।

समाधान:

1. एक var के रूप में घोषित panGestureRecognizer, जिसका अर्थ यह nil का डिफ़ॉल्ट मान है जिसे आप super.init(coder: aDecoder) बुला के बाद बदल सकता दिया जाएगा।

2. मेरी राय, बेहतर समाधान में: एक परोक्ष unwrapped वैकल्पिक का उपयोग करें और UIPanGestureRecognizer() की एक प्रारंभिक मूल्य के साथ panGestureRecognizer नहीं घोषित करते हैं।तब super.init के बाद लक्ष्य रखा कहा जाता है:

class SubView: UIView { 
    let panGestureRecognizer = UIPanGestureRecognizer() 

    required init(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     panGestureRecognizer.addTarget(self, action: Selector("panAction:")) 
    } 
} 
+0

मुझे आपका दूसरा समाधान पसंद है। यह इस मामले के लिए अच्छी तरह से काम करता है जहां आप कोड के बाद के हिस्से में कर सकते हैं। – Pette

+0

मुझे आपका दूसरा समाधान पसंद है और पसंद है। यह इस मामले के लिए अच्छा काम करता है जहां आप कोड के बाद के हिस्से में लक्ष्य निर्धारित कर सकते हैं। कुछ अन्य मामलों के लिए, हालांकि, इस तरह से ऐसा करने का मौका नहीं हो सकता है। उदाहरण के लिए, 'UGynamicAnimator' के साथ 'panGestureRecognizer' को प्रतिस्थापित करें। इस मामले में, संदर्भ दृश्य केवल उदाहरण बनाने पर सेट किया जा सकता है (उदाहरण के लिए 'self.animator = UIDynamicAnimator (संदर्भ दृश्य: स्वयं) ' – Pette

+0

यह एक अच्छा बिंदु है। उस स्थिति में आपको शायद एक चर का उपयोग करना होगा, निहित रूप से अनचाहे वैकल्पिक और 'super.init' के बाद इसका मूल्य निर्धारित करें। या, आप 'आलसी' चर का उपयोग कर सकते हैं - रॉबर्ट वोजा के जवाब पर एक नज़र डालें। इसके अलावा, अगर आपको यह महसूस होता है, या किसी भी उत्तर में आपकी समस्या हल हो जाती है, तो क्या आप एक को सही के रूप में चिह्नित करने पर विचार करें। – ABakerSmith

3

इस विशेष मामले का संभावित हल होगा:

class SubView: UIView { 

let pandGestureRecognizer: UIPanGestureRecognizer 

required init(coder aDecoder: NSCoder) { 
    self.pandGestureRecognizer = UIPanGestureRecognizer() 
    super.init(coder: aDecoder) 
    self.pandGestureRecognizer.addTarget(self, action: "panAction:") 
} 

func panAction(gesture: UIPanGestureRecognizer) { 
    // ... 
} 

}

+0

हां, यह वही है जो मैं कहने जा रहा था। लेट वैरिएबल को तत्काल होने के बाद लक्ष्य जोड़ने से नहीं रोकना चाहिए। – Fogmeister

+0

का उपयोग करने से आप तुरंत लक्ष्य के बाद एक लक्ष्य जोड़ना बंद नहीं करते हैं – ABakerSmith

+0

यह सही है, चलिए इसे तत्काल करने के बाद लक्ष्य जोड़ने से नहीं रोकते हैं। चूंकि 'यूआईपीएनजीस्टर रिकॉन्नाइज़र' एक परिवर्तनीय उदाहरण है। –

4

आप self उपयोग नहीं कर सकते जब तक कि वर्ग आरंभ नहीं हो जाता। और यदि आप प्रॉपर्टी प्रारंभिकरण के लिए self का उपयोग करना चाहते हैं, तो यह lazy होना चाहिए। लेकिन lazylet के लिए समर्थित नहीं है, बस var

ऐसा इसलिए है क्योंकि:

You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

यह समझौते की तरह है और यदि आप निजी सेटर के साथ रह सकते हैं, तो आप ऐसा कर सकते हैं:

class SubView: UIView { 

    private(set) lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in UIPanGestureRecognizer(target: self, action: "panAction:") }() 

    required init(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    } 

    func panAction(gesture: UIPanGestureRecognizer) { 
    } 
} 

या बस UIPanGestureRecognizer() साथ panGestureRecognizer प्रारंभ और बाद में लक्ष्य जोड़ने।

0

यदि आप किसी वस्तु के प्रारंभकर्ता को स्वयं को पास करना चाहते हैं, तो आपको अपनी वस्तु को आलसी घोषित करना चाहिए। क्योंकि जब यह ऑब्जेक्ट प्रारंभ होता है, तो स्वयं अभी तक तैयार नहीं होता है।

lazy var viewModel = IntroViewModel(controller: self) 

class IntroViewModel { 

    private weak var controller: IntroViewController? 

    init(controller: IntroViewController?) { 
     self.controller = controller 
    } 
} 
संबंधित मुद्दे