2016-12-05 10 views
6

मैं एक्सकोड खेल के मैदान के साथ त्वरित बंद परीक्षण का परीक्षण कर रहा था। बंद से क्या उम्मीद है, एक आत्म निहित हैस्विफ्ट बंद क्यों स्वयं को पकड़ नहीं लेते?

import UIKit 

class A{ 
    var closure:()->() = {} 

    var name: String = "A" 
    init() { 
     self.closure = { 
      self.name = self.name + " Plus" 
     } 
    } 

    deinit { 
     print(name + " is deinit") 
    } 
} 

var a: A? 
a = A() 
a = nil 

के रूप में, तो एक कभी नहीं जारी किया जाता है:

यह मेरा कोड है।

लेकिन, जब मैं अंतिम पंक्ति से पहले इस पंक्ति जोड़ें: फिर

a?.closure = { a?.name = "ttt" } 

, मैंने पाया "एक deinit है" उत्पादन खिड़की है, जो एक जारी की है इसका मतलब है। क्यों? एक रीसायकल संदर्भ नहीं है?

परीक्षण होने के लिए, मैं एक समारोह का उपयोग बंद है, जो कोड संस्करण 2 है स्थापित करने के लिए:

import UIKit 

class A{ 
    var closure:()->() = {} 
    func funcToSetClosure(){ 
     self.closure = { self.name = "BBB"} 
    } 
    var name: String = "A" 
    init() { 
     self.closure = { 
      self.name = self.name + " Plus" 
     } 
    } 

    deinit { 
     print(name + " is deinit") 
    } 
} 



var a: A? 


a = A() 


a?.funcToSetClosure() 


a = nil 

फिर, एक कभी नहीं जारी किया गया है।

तो मुझे निष्कर्ष मिला, जब बंद में कक्षा में एक समारोह या एक समारोह द्वारा बंद किया जाता है, तो यह रीसायकल संदर्भ का कारण बनता है, जब इसे कक्षा के बाहर सेट किया जाता है, तो यह रीसायकल संदर्भ नहीं देगा। क्या मैं सही हू?

उत्तर

4

वहाँ दोनों ही मामलों में चक्र को बनाए रखने रहे हैं। अंतर संदर्भ की प्रकृति है, जगह जहां closure सेट है।

  • "अंदर" स्थिति में, बंद के अंदर संदर्भ self है: यह क्या फर्क यह तोड़ चक्र पर ले जाता है में प्रकट होता है। जब आप a पर अपना संदर्भ जारी करते हैं, तो चक्र को तोड़ने के लिए अपर्याप्त है, क्योंकि चक्र सीधे आत्म-संदर्भित है। चक्र को तोड़ने के लिए, a.closurenil को से nil पर सेट करने से पहले, और आपने ऐसा नहीं किया था।

enter image description here

  • "बाहर" स्थिति में, संदर्भ a है। तब तक एक बरकरार चक्र होता है जब तक आपका a संदर्भ nil पर सेट नहीं होता है। लेकिन आप अंततः इसे nil पर सेट करें, जो चक्र को तोड़ने के लिए पर्याप्त है।

enter image description here

(चित्र Xcode की स्मृति ग्राफ सुविधा से आते हैं। तो शांत।)

+0

आपकी मदद के लिए धन्यवाद, अंततः मैं समझता हूं, और एक्सकोड के मेमोरी ग्राफ के लिए भी धन्यवाद। –

2

क्लिनर चक्र का कारण क्या है कि आप बंद होने में self का संदर्भ देते हैं।

var a: A? 
a = A() 
a?.closure = { a?.name = "ttt" } 
a = nil 

आप बंद बदल नहीं रह संदर्भ के लिए self, यही कारण है कि यह पुनः आवंटित की जाती है।

अंतिम उदाहरण में, आप इसे बंद करने में फिर से self संदर्भित करते हैं, यही कारण है कि यह अस्वीकार नहीं करता है। इसके आस-पास के तरीके हैं, यह पोस्ट स्विफ्ट में प्रत्येक मामले का उपयोग करने की एक महान सूची है: How to Correctly handle Weak Self in Swift Blocks with Arguments

मुझे लगता है कि आप इस तरह कुछ ढूंढ रहे हैं, जहां आप ब्लॉक के अंदर स्वयं को कमजोर संदर्भ का उपयोग करते हैं। स्विफ्ट के पास ऐसा करने के कुछ नए तरीके हैं, जो आमतौर पर ब्लॉक के सामने [unowned self] नोटेशन का उपयोग करते हैं। यहाँ क्या हो रहा है पर

init() { 
    self.closure = { [unowned self] in 
     self.name = self.name + " Plus" 
    } 
} 

अधिक पढ़ने: Shall we always use [unowned self] inside closure in Swift

+0

धन्यवाद, मैं उन्हें सब पढ़ूंगा। –

2

SIL documentation के रूप में कहते हैं, जब आप एक बंद में एक स्थानीय चर पर कब्जा, यह ढेर पर संग्रहीत किया जाएगा संदर्भ गिनती के साथ:

कब्जा कर लिया स्थानीय चर और indirect मूल्य प्रकार के पेलोड ढेर पर जमा हो जाती है। प्रकार @box T एक संदर्भ-गणना प्रकार है जो एक बॉक्स को संदर्भित करता है जिसमें T प्रकार का एक परिवर्तनीय मान होता है।

आप इसलिए जब कहते हैं:

var a : A? = A() 
a?.closure = { a?.name = "ttt" } 

आप एक संदर्भ चक्र (जो आप आसानी से सत्यापित कर सकते हैं) है है। ऐसा इसलिए है क्योंकि A के उदाहरण में closure संपत्ति का संदर्भ है, जिसमें ढेर-आवंटित बॉक्स किए गए A? उदाहरण (इस तथ्य के कारण कि यह बंद होने पर कब्जा कर लिया जा रहा है) का संदर्भ है, जिसके बदले में उदाहरण का संदर्भ है A का।

लेकिन, आप तो कहते हैं:

a = nil 

कौन सा .none को ढेर-आवंटित बॉक्सिंग A? उदाहरण के मूल्य निर्धारित करता है, इस प्रकार जिसका अर्थ है कि तुम अब एक संदर्भ चक्र है, A के कहने के लिए अपने संदर्भ रिहा इसलिए , और इस प्रकार A को हटाया जा सकता है।

बस, a = nil बताए नहीं संदर्भ चक्र टूट जाएगा बिना क्षेत्र से बाहर a गिरावट दे ढेर पर A? का उदाहरण अभी भी A की closure संपत्ति, है जो अभी भी A? के पास आया द्वारा बनाए रखा जा रहा है के रूप में उदाहरण।

+0

धन्यवाद, मैं अब एसआईएल दस्तावेज पढ़ रहा हूं। –

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