2015-01-04 5 views
9

कहते हैं कि स्विफ्ट में मैं एक सी सरणी मैन्युअल का निर्माण और, इसे पारित इस तरह करते हैं:एक स्विफ्ट UnsafeMutablePointer मैन्युअल रूप से निर्माण करते समय, आवंटन के बाद अनिवार्य/dealloc अनिवार्य है?

override func drawRect(rect: CGRect) { 
    let c = UIGraphicsGetCurrentContext() 
    var arr = UnsafeMutablePointer<CGPoint>.alloc(4) 
    arr[0] = CGPoint(x:0,y:0) 
    arr[1] = CGPoint(x:50,y:50) 
    arr[2] = CGPoint(x:50,y:50) 
    arr[3] = CGPoint(x:0,y:100) 
    CGContextStrokeLineSegments(c, arr, 4) 
} 

(मैं जानता हूँ कि मैं नहीं कि क्या करना है, लेकिन सिर्फ मेरे साथ सहन करते हैं।) मैं तो इस UnsafeMutablePointer पर destroy और/या dealloc पर कॉल न करें, क्या मैं चार CGPoints के लिए स्मृति को लीक कर रहा हूं? यदि आप आवंटित लेकिन पुनःआवंटन नहीं है

///      This type provides no automated 
/// memory management, and therefore the user must take care to allocate 
/// and free memory appropriately. 

तो, आप स्मृति रिसाव हो जाएगा:

+0

क्या आप मेमोरी लीक की जांच के लिए एक्सकोड का उपयोग नहीं कर सकते? – michaelsnowden

+0

यदि आप 'arr.dealloc (4) 'को कॉल नहीं करते हैं तो आप स्मृति को रिसाव करेंगे। यह एक अच्छा अवलोकन (शायद एक डुप्लिकेट) लगता है: http://stackoverflow.com/questions/27670643/confusion-regarding-terminology-concerning-unsafemutablepointers-destroy –

+0

@doctordoder क्या आपने इसे आजमाया? यहां कोई CGPoint ऑब्जेक्ट्स नहीं हैं - यह कहीं स्मृति की एक ब्लॉक है, इसलिए मैं इसे स्मृति के सभी ब्लॉक में आसानी से नहीं चुन सकता। – matt

उत्तर

11

UnsafeMutablePointer के लिए दस्तावेज़ बहुत स्पष्ट है। पॉइंटर ऑब्जेक्ट के विनाश पर कोई ऑटो-डीलोकेशन नहीं है।

पुन कि क्या आप deallocating से पहले नष्ट कर देना चाहिए, यह भी बहुत स्पष्ट है:

/// The pointer can be in one of the following states: 
/// 
/// - memory is not allocated (for example, pointer is null, or memory has 
/// been deallocated previously); 
/// 
/// - memory is allocated, but value has not been initialized; 
/// 
/// - memory is allocated and value is initialized. 

लेकिन भालू मन में आप आगे और पीछे इन राज्यों के बीच परिवर्तन कर सकते हैं। तो ऑब्जेक्ट करने के बाद वस्तुओं को डी-प्रारंभिक (उर्फ नष्ट करना) शुरू करना, स्मृति अब "प्रारंभिक" स्थिति में नहीं है, ताकि आप इसे फिर से शुरू या रद्द कर सकें। आप कभी भी प्रारंभ किए बिना आवंटित कर सकते हैं, फिर रद्द कर सकते हैं।

और जब dealloc बुला:

/// Deallocate `num` objects. 
... 
/// Precondition: the memory is not initialized. 
/// 
/// Postcondition: the memory has been deallocated. 

इसलिए आप चाहिए कॉल dealloc कॉल करने से पहले किसी भी initialized वस्तुओं पर नष्ट कर। आप शायद उसमें सही हैं क्योंकि CGPoint की तरह कुछ पूरी तरह से निष्क्रिय है (केवल दो फ़्लोटिंग पॉइंट अंकों की एक स्ट्रक्चर) शायद पर कॉल करने से पहले destroy पर कॉल करने के लिए कोई नुकसान नहीं करता है लेकिन आप बिना जाने निश्चित नहीं हो सकते कार्यान्वयन (पॉइंटर स्ट्रक्चर और कंपाइलर दोनों का संभवतः, क्योंकि मानक lib lib भाषा का अर्ध-भाग है, वहां कुछ बेक्ड-इन ऑप्टिमाइज़ेशन हो सकते हैं), और आम तौर पर, यह केवल एक अच्छी आदत नहीं है। जल्द या बाद में आप String को नष्ट करना भूल जाएंगे, और फिर आपको खेद होगा।

यदि आप UnsafePointer द्वारा स्मृति के स्वचालित स्वयं सफाई के कुछ प्रकार के लिए उम्मीद कर रहे थे (इस में से कोई भी move संचालन btw जो पुराने स्मृति को नष्ट करने के साथ नए स्मृति आरंभ गठबंधन के लिए खातों), मुझे नहीं लगता कि यह एक के रूप में संभव होगा) यह एक संरचना है, इसलिए deinit को दायरे से बाहर निकलने पर स्वत: डिलीकेट करने के लिए लागू नहीं किया जा सकता है, और बी) यह अपने आकार को ट्रैक नहीं करता है - आपको यह ट्रैक करना होगा कि आप कितना आवंटित करते हैं, और deallocate पर कॉल में स्पष्ट रूप से वापस आपूर्ति करें।

मानक लाइब्रेरी में कुछ ऐसा है जो आपको स्वयं को ऐसा करने के बिना स्मृति को स्वत: डिलीकेट करता है - HeapBufferStorage, मानक लाइब्रेरी में एक और एकमात्र कक्षा। संभवतः यह deinit के कार्यान्वयन से लाभ प्राप्त करने के लिए विशेष रूप से एक वर्ग है। इसे प्रबंधित करने के लिए HeapBuffer भी है, और इसमें एक आसान isUniquelyReferenced() फ़ंक्शन है जो आपको यह बताने की अनुमति देता है कि इसकी प्रतिलिपि बनाई गई है (भले ही यह एक संरचना है) और इसलिए आपको ऐरे और तारों के समान प्रति-लिखने की क्षमता लागू करने की अनुमति मिल जाएगी।

+0

मार्टिन आर के विचार को दोहराए जाने वाले टाइमर के विचार को मेरे दृश्य के कारण होने के कारण मैं स्मृति उपयोग में स्थिर वृद्धि देखता हूं चाहे मैं 'नष्ट' और 'dealloc' कहूं या नहीं। इस प्रकार मैं मुझे विश्वास नहीं है कि इससे कोई फर्क पड़ता है। – matt

+1

दिमाग में ध्यान दें, सिर्फ इसलिए कि आप रनटाइम के साथ रनटाइम पर वापस मेमोरी देते हैं इसका मतलब यह नहीं है कि रनटाइम इसे सीधे ओएस पर दे देगा ... –

5

स्विफ्ट 2 UnsafeMutablePointer में नए defer कीवर्ड के साथ alloc/dealloc साथ जोड़ी बना थोड़ा कम निराशा बनाया जा सकता है:

let ptr = UnsafeMutablePointer<T>.alloc(1) 
defer { ptr.dealloc(1) } 
+0

क्या अगर मैं मस्ती के बजाय कक्षा में एक var घोषित करता हूं? क्या मुझे 'deinit' फ़ंक्शन को कार्यान्वित करना चाहिए और 'नष्ट करें' और फिर 'dealloc' को कॉल करना चाहिए? –

0

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

override func drawRect(rect: CGRect) { 
    if let c = UIGraphicsGetCurrentContext() 
    { 
     let arr = [CGPoint(x:0,y:0), CGPoint(x:50,y:50), CGPoint(x:50,y:50), CGPoint(x:0,y:100)] 
     CGContextStrokeLineSegments(c, arr, 4) 
    } 
} 
+0

प्रश्न बताता है: "मुझे पता है कि मुझे ऐसा करने की ज़रूरत नहीं है, लेकिन बस मेरे साथ सहन करें" तो आप विषय से बाहर हैं – matt

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