5

क्या कोई यह बता सकता है कि यह क्यों रिसाव नहीं करता है?स्विफ्ट - बंद करने में स्वयं को कैप्चर करने के बाद रिसाव की उम्मीद

मैं एक closure भीतर self पर कब्जा कर रहा हूँ तो मैं दो मजबूत संकेत एक दूसरे को इशारा कर दिया होता, इसलिए, deinit संदेश नहीं कभी व्यक्ति वस्तु के लिए बुलाया जाना चाहिए।

सबसे पहले, यह मेरी कक्षा व्यक्ति है:

class Person { 
    var name: String 
    init(name: String) { self.name = name } 
    deinit { print("\(name) is being deinitialized") } 
} 

और ये मेरे ViewController के कार्यान्वयन है:

class ViewController: UIViewController { 

    var john:Person? 

    func callClosureFunction(closure:(name:Bool) ->()) { 
     closure(name: true) 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     john = Person(name:"John") 

     self.callClosureFunction { (name) in 

      self.john?.name = "John Appleseed" 
      self.john = nil 

      // xcode prints - John Appleseed is being deinitialized 
     } 

    } 

} 

मैं कर समस्या का समाधान करने में सक्षम होने की उम्मीद कर रहा था:

self.callClosureFunction { [weak self] (name) in ... 

लेकिन यह भी आवश्यक नहीं था। क्यूं कर?

उत्तर

3

चूंकि आपका व्यू कंट्रोलर बंद नहीं है बंद करने के लिए, कोई परिपत्र संदर्भ नहीं है। यदि आप यह लिखा:

class ViewController: UIViewController { 

    var john:Person? 
    var closure:(Bool)->()? 

    func callClosureFunction(closure:((name:Bool) ->())?) { 
     closure?(name: true) 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     john = Person(name:"John") 
     closure = { (name) in 

      self.john?.name = "John Appleseed"  

      // Because this closure will never be released, the instance of Person will never deinit either 
     } 
     self.callClosureFunction(closure) 
    } 
} 

उसके बाद दृश्य नियंत्रक बंद बनाए रखने होगा और बंद self करने के लिए अपने संदर्भ के माध्यम से दृश्य नियंत्रक को बनाए रखने होगा। इसलिए, न तो जारी किया जाएगा, और यदि आप स्पष्ट रूप से self.john = nil (जो आपने अपने मूल उदाहरण में किया था) सेट नहीं किया है, तो Person उदाहरण कभी भी deninit नहीं कहा जाएगा।

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

+1

'जॉन एप्लासेड' व्यक्ति का ऑब्जेक्ट अभी भी समाप्त हो जाएगा। मेरा उत्तर – Alexander

+0

@AlexanderMomchliov देखें यदि बंदरगाह वीसी (स्वयं) को बरकरार रखता है और वीसी मेरे उदाहरण के रूप में बंद रहता है, तो वीसी कभी जारी नहीं होता है (न ही बंद हो जाता है)। यदि वीसी कभी खत्म नहीं होता है, तो यह कभी भी व्यक्ति वस्तु के संदर्भ को जारी नहीं करता है, जिसका अर्थ है कि व्यक्ति वस्तु कभी भी कम नहीं होती है। –

+1

कोई फर्क नहीं पड़ता कि एक बरकरार चक्र है या नहीं। 'जॉन' स्पष्ट रूप से 'शून्य' पर सेट है, अंतिम संदर्भ को हटा रहा है, इस प्रकार एआरसी को इसे 'deinit' करने का कारण बनता है। – Alexander

0

आप self पर कब्जा कर रहे हैं जो ViewController पर इंगित करता है, लेकिन आप Person उदाहरण के बारे में सोच रहे हैं।

Person वास्तव में परिपत्र संदर्भित नहीं है और इसलिए डी-इनटाइलाइज्ड हो जाता है और जब आप इसे बंद करने के अंत में शून्य पर सेट करते हैं तो ठीक ठीक हो जाता है।

deinitViewController के लिए लागू करें और देखें कि यह कैसे काम करता है।

0

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

नहीं, आपके पास self बंद होने से एक मजबूत सूचक है। बंद होने से self पर कोई चक्रीय संदर्भ नहीं है। इस प्रकार, आपके पास directed acylic graph है, जो एआरसी के लिए कोई समस्या नहीं है।

हालांकि, आपका प्रयोग त्रुटिपूर्ण होने से त्रुटिपूर्ण है। यहां तक ​​कि अगर बंद कर दिया गया था, तो John AppleseedPerson ऑब्जेक्ट अभी भी deinit होगा। इस ऑब्जेक्ट का जीवन चक्र विशेष रूप से john संदर्भ पर आपके ViewController से संदर्भित है। जब आप nil पर उस संदर्भ को सेट करते हैं, तो आप John Appleseed ऑब्जेक्ट का अंतिम संदर्भ निकाल रहे हैं, इस प्रकार इसे हटा दिया गया है।

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

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