2015-01-21 6 views
10

जब प्रत्यावर्तन में एक संपत्ति परिणामों की didSet पर्यवेक्षक अधिभावी में अधिभावी didSet परिणाम है, क्यों?स्विफ्ट: एक प्रत्यावर्तन

class TwiceInt { 
    var value:Int = 0 { 
     didSet { 
      value *= 2 
     } 
    } 
} 

class QuadInt : TwiceInt { 
    override var value:Int { 
     didSet { 
      value *= 4 
     } 
    } 
} 

let t = TwiceInt() 
t.value = 5 // this works fine 


let q = QuadInt() 
q.value = 5 // this ends up in recursion 

अगर मैं अद्यतन

class QuadInt : TwiceInt { 
    override var value:Int { 
     didSet { 
      super.value *= 4 
     } 
    } 
} 

q.value = 5 // q.value = 80 

तो मैं कॉल लगता QuadInt साथ रहने के लिए कुछ की तरह:

value = 5 
QuadInt:didSet (value *= 4) 
value = 20 
TwiceInt:didSet (value *= 2) 
value = 40 
TwiceInt:didSet (value *= 2) 
value = 80 

यह कम या ज्यादा अंधेरे में शूटिंग की तरह है। क्या कोई प्रॉपर्टी अपडेट होने पर क्या होता है पर कोई दस्तावेज है?

उत्तर

1
समस्या

बजाय आप सेट का उपयोग करना चाहिए कि आप didSet उपयोग नहीं करना चाहिए मान बदलने के लिए है, क्योंकि यह प्रत्यावर्तन का कारण होगा है:

var TwiceInt : Int { 
    get { 
     return TwiceInt 
    } 
    set (newValue) { 
     TwiceInt *= 2 
    } 
} 
+0

लेकिन अगर ऐसा है, तो क्यों 't = TwiceInt() t.value = 5''' ठीक काम करता है? – chunkyguy

+0

ऐप्पल के स्विफ्ट दस्तावेज के अनुसार, 'डीडसेट' में एक मान बदलने से रिकर्सन नहीं होता है (यह दस्तावेज़ों में क्रियापद है)। – Mecki

3

दोनों didSet ब्लॉक में एक println() लाना, आप देख सकते हैं कि यह बार-बार सुपर-कार्यान्वयन को कॉल करता है, फिर ओवरराइड, फिर सुपर, फिर ओवरराइड ... जब तक यह विस्फोट न हो जाए।

मैं केवल छवि है कि इस स्विफ्ट में एक बग है कर सकते हैं। मुझे स्विफ्ट 1.2 में एक ही समस्या मिलती है (एक्सकोड 6.3 बीटा के साथ बंडल)।


यह निश्चित रूप से कार्य करना चाहिए, कम से कम जैसा कि मैंने इसे पढ़ा है। https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID254 से:

नोट

आप अपने स्वयं के didSet पर्यवेक्षक, नया मान है कि आप एक है कि सिर्फ स्थापित किया गया था की जगह लेगा आवंटित भीतर एक संपत्ति को कोई मान निर्दिष्ट हैं।

और उनके AudioChannel नमूना (नोट नीचे उद्धृत) के बाद:

नोट

इन दो चेकों के पहले में, didSet पर्यवेक्षक एक अलग मान पर currentLevel सेट। हालांकि, पर्यवेक्षक को फिर से बुलाया नहीं जाता है।

struct AudioChannel { 
    static let thresholdLevel = 10 
    static var maxInputLevelForAllChannels = 0 
    var currentLevel: Int = 0 { 
     didSet { 
      if currentLevel > AudioChannel.thresholdLevel { 
       // cap the new audio level to the threshold level 
       currentLevel = AudioChannel.thresholdLevel 
      } 
      if currentLevel > AudioChannel.maxInputLevelForAllChannels { 
       // store this as the new overall maximum input level 
       AudioChannel.maxInputLevelForAllChannels = currentLevel 
      } 
     } 
    } 
} 
1

यह ओवरराइड यह अभी भी बुला रहा है सुपर क्लास didSet के बावजूद किसी कारण से प्रकट होता है।

पहला उदाहरण आप प्रत्यावर्तन में आ सकती है क्योंकि ट्रैक्टर की स्थापना सुपर क्लास didSet जो बारी में सेट quads स्थापित किया था आदि ect सेट में

दूसरा मान सेट उदाहरण में का कारण बनता है दोनों didSets होने के लिये प्रत्येक एक बार, तो ट्रैक्टर भी सुपर didSet के सेट पर पिछली बार didSet।

quad.value = 5

मूल्य = * 2 (सुपर क्लास didSet) * 4 (उपवर्ग didSet) * 2 (सुपर क्लास didSet) = 80

12

आप didSet ओवरराइड नहीं कर सकते, यह एक सामान्य विधि है। वास्तव में आप didSet ओवरराइड नहीं किया था, आप संपत्ति ही overrode।

didSet पर्यवेक्षकों के काम की तरह काम करता है और सिर्फ इसलिए कि आप विरासत संपत्ति पर अपना स्वयं का पर्यवेक्षक सेट करते हैं, इसका मतलब यह नहीं है कि कोई अन्य पर्यवेक्षक स्वचालित रूप से अपंजीकृत नहीं होता है। तो आपके सुपरक्लास का पर्यवेक्षक पूरी तरह से इस अंडे से अप्रभावित है, इस प्रकार didSet दोनों विधियों को अंत में बुलाया जाएगा।

अब यदि आप अपने didSet पर्यवेक्षक में कोई मान बदलते हैं, तो यह पुनरावृत्ति नहीं करेगा क्योंकि स्विफ्ट रनटाइम यह समझने के लिए पर्याप्त स्मार्ट है कि didSet कार्यान्वित करने के कार्यान्वयन के बाद अपनी खुद की मनाई गई संपत्ति को फिर से कॉल करने की उम्मीद नहीं है इसलिए। रनटाइम जानता है कि didSet विधि वर्तमान में निष्पादित कर रही है और इस विधि को वापस करने के पहले परिवर्तनीय परिवर्तनों को फिर से निष्पादित नहीं करेगा। यह चेक सुपरक्लास में काम नहीं कर रहा है।

तो *= 4 सुपर वर्ग पर्यवेक्षक के नाम से जाना है, जो सेट *= 2 का कारण बनता है और कहा कि उपवर्ग पर्यवेक्षक, फिर से के नाम से जाना जो फिर सुपर वर्ग पर्यवेक्षक के कारण *= 4 सेट हो जाएगा फिर से कहा जा करने का कारण बनता ... और इतने पर ।

स्पष्ट रूप से super का उपयोग करके, आप उस चक्र को तोड़ते हैं, क्योंकि अब आप अपनी ओवरराइड संपत्ति सेट नहीं कर रहे हैं, लेकिन विरासत में सुपर संपत्ति है और आप वास्तव में उस सुपर प्रॉपर्टी को नहीं देख रहे हैं, आप केवल अपना खुद का ओवरराइड देख रहे हैं।

आप कुछ भाषाओं में ओवरराइड विधियों के साथ एक ही समस्या में भाग सकते हैं, जहां सामान्य समाधान भी कॉल में से किसी एक पर super का स्पष्ट रूप से उपयोग करना है।

संबंधित मुद्दे