2016-09-11 5 views
14

मैंने देखा है कि स्विफ्ट 2.2 में, @noescape के साथ गैर-भागने के रूप में चिह्नित क्लोज़ को स्पष्ट self की आवश्यकता नहीं है। स्विफ्ट 3 में, सभी बंद डिफ़ॉल्ट रूप से गैर-भाग रहे हैं और अब उन्हें @escaping के साथ चिह्नित करने की आवश्यकता है यदि आप चाहते हैं कि वे भागने में सक्षम हों।स्विफ्ट 3 में डिफॉल्ट रूप से सभी गैर-भागने के दौरान क्लोजर को स्पष्ट 'स्वयं' की आवश्यकता क्यों होती है?

यह देखते हुए कि डिफ़ॉल्ट रूप से स्विफ्ट 3 में सभी बंद होने से बच निकल रहे हैं, उन्हें एक स्पष्ट self क्यों चाहिए?

final class SomeViewController: NSViewController { 

    var someClosure:() ->() = { _ in } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     someClosure = { 
      view.layer = CALayer() // ERROR: Implicit use of `self` in closure; use `self.` to make capture semantics explicit 
     } 
    } 
} 

उत्तर

9

स्विफ्ट 3 में, सब बंद डिफ़ॉल्ट रूप से गैर भागने हैं

नहीं, स्विफ्ट 3 में, केवल बंद समारोह तर्क (यानी समारोह आदानों कि कार्यों के लिए खुद कर रहे हैं) द्वारा गैर बचने कर रहे हैं डिफ़ॉल्ट (SE-0103 के अनुसार)। उदाहरण के लिए:

class A { 

    let n = 5 
    var bar :() -> Void = {} 

    func foo(_ closure:() -> Void) { 
     bar = closure // As closure is non-escaping, it is illegal to store it. 
    } 

    func baz() { 
     foo { 
      // no explict 'self.' required in order to capture n, 
      // as foo's closure argument is non-escaping, 
      // therefore n is guaranteed to only be captured for the lifetime of foo(_:) 
      print(n) 
     } 
    } 
} 

ऊपर के उदाहरण में closure के रूप में गैर एस्केपिंग, यह संग्रहीत या कब्जा कर लिया है, इस प्रकार समारोह foo(_:) के जीवनकाल को अपने जीवनकाल सीमित करना प्रतिबंधित किया जाता है। इसका मतलब यह है कि किसी भी मूल्य को कैप्चर करने के बाद यह सुनिश्चित किया जाता है कि फ़ंक्शन से बाहर निकलने के बाद कब्जा नहीं किया जाता है - जिसका अर्थ है कि आपको कैप्चरिंग के साथ होने वाली समस्याओं के बारे में चिंता करने की आवश्यकता नहीं है, जैसे कि चक्र बनाए रखना।

हालांकि, एक बंद संग्रहीत संपत्ति (उपरोक्त उदाहरण में bar जैसे) परिभाषा से बचने (यह @noescape साथ में चिह्नित करने के अतर्कसंगत होगा) अपने जीवनकाल के रूप में कर रहा है नहीं किसी दिए गए कार्य करने के लिए सीमित है - यह (और इसलिए इसके सभी कब्जे वाले चर) स्मृति में तब तक बने रहेंगे जब तक दिया गया उदाहरण स्मृति में रहता है। इसलिए यह आसानी से चक्रों को बनाए रखने जैसी समस्याओं का कारण बन सकता है, यही कारण है कि कैप्चरिंग सेमेन्टिक्स को स्पष्ट करने के लिए आपको एक स्पष्ट self. का उपयोग करने की आवश्यकता है।

तथ्य, बिंदु में मामले में, अपने उदाहरण कोड viewDidLoad() पर एक चक्र को बनाए रखने का निर्माण करेगा बुलाया जा रहा है, के रूप में someClosure दृढ़ता से self कैप्चर करता है, और self दृढ़ता का संदर्भ someClosure, के रूप में यह एक संग्रहीत संपत्ति है।


बेशक

, एक जगह है जहाँ आप @noescape विशेषता का उपयोग करने में सक्षम होने की उम्मीद होती है एक बंद एक समारोह में एक स्थानीय चर है कि चल रहा है। इस तरह के बंद होने पर एक अनुमानित जीवनकाल होगा, जब तक कि यह फ़ंक्शन के बाहर संग्रहीत न हो, या कब्जा कर लिया जाए। उदाहरण के लिए:

class A { 

    let n = 5 

    func foo() { 

     let f : @noescape() -> Void = { 
      print(n) 
     } 

     f() 
    } 
} 

दुर्भाग्य से, के रूप में @noescape स्विफ्ट 3 में हटाया जा रहा है, यह संभव हो जाएगा (दिलचस्प बात यह है कि Xcode 8 जीएम में, यह संभव है, लेकिन एक प्रतिवाद चेतावनी पैदावार है)। Jon Shier says के रूप में, हमें उस भाषा में फिर से जोड़ने के लिए इंतजार करना होगा, जो हो सकता है या नहीं भी हो सकता है।

+0

स्पष्टीकरण के लिए धन्यवाद! बस स्पष्ट करने के लिए, जब दृश्य नियंत्रक स्वयं को हटा दिया जाता है, तो बंद होने और दृश्य को भी हटा दिया जाएगा, या क्या वे स्मृति रिसाव का कारण बनेंगे? – beingadrian

+0

@beingadrian यदि आपकी 'someClosure' संपत्ति को बंद कर दिया गया है जो दृढ़ता से' स्वयं '(जैसे कि आपके दृश्य में' viewDidLoad') को कैप्चर करता है, तो यह वास्तव में एक बनाए रखने वाला चक्र बनाएगा, और इसलिए कोई अन्य मजबूत नहीं होने पर रिसाव होगा आपके व्यू कंट्रोलर के संदर्भ (आप अपने व्यू कंट्रोलर क्लास में 'प्रिंट' स्टेटमेंट के साथ 'डीनिट' को लागू करके इसे स्वयं सत्यापित कर सकते हैं)। सबसे आसान समाधान 'स्वयं' को 'कमजोर' के रूप में कैप्चर करना होगा (बंद करें {{[कमजोर स्वयं] ...} 'के रूप में बंद करें। फिर आप दृश्य की परत को निर्दिष्ट करने के लिए बंद होने में वैकल्पिक चेनिंग का उपयोग कर सकते हैं, 'स्वयं? .view.layer = CALayer() ' – Hamish

+0

@beingadrian एक और संभावित समाधान' अनूठा 'के रूप में बंद होने में' स्वयं 'को पकड़ना है, हालांकि यह है संभवतः खतरनाक है क्योंकि व्यू कंट्रोलर इंस्टेंस आवंटित होने के बाद बंद होने पर बंद हो जाएगा। इसलिए मैं केवल यह करने की सलाह दूंगा कि 'कुछ क्लोजर' एक 'निजी' संपत्ति थी (तब किसी अन्य वर्ग का संदर्भ प्राप्त करने का कोई मौका नहीं है)। – Hamish

4

संग्रहीत बंद डिफ़ॉल्ट रूप से बचने के लिए माना जाता है, भले ही वे वास्तव में नहीं हैं। उन्हें गैर-भागने को चिह्नित करने का कोई तरीका नहीं है, इसलिए जब तक वे @noescape भाषा में वापस नहीं आते, तब तक हम इस तरह फंस जाते हैं, जो वे कर सकते हैं या नहीं कर सकते हैं। तेजी से विकास मेलिंग सूची पर this discussion देखें।

+0

यह दिलचस्प है। मुझे उम्मीद है कि वे कम से कम एक अद्यतन में इसे स्पष्ट कर देंगे।जवाब के लिए धन्यवाद! – beingadrian

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

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