2010-02-22 9 views
6

मैं अपने * ज फ़ाइल में मेरी सरणी की घोषणा:सही तरीका घोषित करने के लिए, alloc, लोड, और dealloc एक NSMutableArray

 
@interface aViewController: UIViewController 
{ 
    NSMutableArray *anArray; // You will need to later change this many times. 
} 
@end 

मैं इसके लिए स्मृति alloc मेरी * .m फ़ाइल:

 
-(void) viewDidLoad 
{ 
    anArray = [[NSMutableArray alloc] init]; 
} 

मैं एक परीक्षण बटन पर क्लिक करें मेरी सरणी लोड करने के लिए (अंततः इसे प्रत्येक क्लिक पर differnt मूल्यों लोड करने के लिए की आवश्यकता होगी):

 
    anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; 

और मैं इसे यहां मुक्त करता हूं:

 
-(void) dealloc 
{ 
    [anArray release]; 
    [super dealloc]; 
} 

क्या यह सब ठीक दिखता है?

यह दुर्घटनाओं क्योंकि जब मैं बाद में इस कोड चलाएँ:

 
    NSLog(@"%d", [anArray count]); 

सुनिश्चित नहीं हैं कि क्यों एक साधारण "NSLog() और गिनती" सब कुछ दुर्घटना होगा।


एक प्रकार की कटार,

मुझे इसे इस तरह से रख दो: मैं संकेत दिए गए, सरणियों, स्ट्रिंग्स और स्मृति का एक विशाल गलतफहमी है।

मैंने जो कुछ भी पाया है उसे पढ़ा है ... लेकिन (अभी तक) एक सरल, स्पष्ट, आसानी से समझने वाला वर्णन ढूंढना है।

क्या आप एक सुझाव दे सकते हैं? (उम्मीद है कि पढ़ने के 10 से कम पेज।) क्या कोई संदर्भ है जो जस्ट इस विषय को बताता है ... और "आपके पास कोडिंग अनुभव के 12 साल हैं ... लेकिन किसी ने कभी भी स्मृति आवंटित करने के साथ निपटाया है या नहीं पॉइंटर्स "।)

तो परिवर्तनीय-नाम जिस तरह से मैं ऑब्जेक्ट को संदर्भित करता हूं? फिर यह क्यों है?

मैं कई अन्य भाषाओं कि सिर्फ यह करने के लिए इस्तेमाल किया है:

 
myString = "this" 
myString = "that" 

myInt = 5 
myInt = 15 

(सरल हो सकता है क्या।)


मेरे लिए ऐसा लगता है कि यह करने के लिए सबसे आसान तरीका होगा इस। (और यह काम करने लगता है लेकिन यह वास्तव में सही है।?)

 
Don't alloc any memory for my NSMutableArray initially. 
Don't re-alloc any memory repeatedly. (When I change my array's values.) 
Don't release it repeatedly. (Before I change my array's values.) 
Don't release it when I exit the program. 

But: 
Always remember to use RETAIN when I initially assign 
(and repeatedly reassign) new values to my anArray variable. 

आप anArray = [NSMutableArray arrayWithObjects के साथ अपने सरणी लोड हो रहा है नहीं कर रहे हैं: @ "एक", @ "दो" , @"तीन खाली]; इसके बजाय, आप एक नया उदाहरण इसकी जगह जाता है, और भी बदतर: एक उदाहरण है, जिसका संदर्भ वास्तव में कुछ इकाई के स्वामित्व में है के साथ

वाह नियंत्रित नहीं करते। तो मेरे पास 20 सरणी हो सकती हैं ... सभी को एक ही नाम कहा जाता है: anArray ... और वे सभी अलग होंगे?(ग्लोबल सरणी जैसी कोई चीज़ नहीं है?)

आदि पुराने मानों को साफ़ करने के लिए, विधि हटाएंऑलऑब्जेक्ट आसान हो सकता है। उत्परिवर्तन विधियां भी हैं, जिनका उपयोग कई मानों को एक साथ में जोड़ने के लिए किया जा सकता है।

तो ... पहले मैं "सभी वस्तुओं को हटाने" करने के लिए है ... और फिर मैं एक विधि यह सब मेरी नए मूल्यों को फिर से जोड़ने के कॉल कर सकते हैं।

anArray = [[NSMutableArray arrayWithObjects: @ "one", @ "two", @ "three", nil] retain]; आवंटन/init अनुक्रम के बजाय ।

वाह। मैंने सोचा कि इसके लिए जगह आवंटित किए बिना किसी सरणी में कुछ भी संग्रहीत नहीं किया जा सकता है।

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

विचार कर सकते हैं मैं गुण का उपयोग कर कि क्या करना होगा कैसे?

 
> anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; 
> anArray = [NSMutableArray arrayWithObjects:@"four", @"five", @"six", nil]; 

वैसे ही जैसे मैं क्या करना होगा:

 
x = 12; 
x = 24; 

वाह
इस तरह कुछ करने के लिए सही तरीका क्या होगा। मैं वास्तव में तारों, सरणी और स्मृति के बारे में सब कुछ पूरी तरह गलत समझता है। मैंने सोचा था कि "आसान तरीका" एक बार आवंटित किया गया था ... म्यूटेबल सरणी का उपयोग करें ... जितना चाहें उतना बदलें ... और इसे एक बार मुक्त करें।

ऐसा करने के साथ समस्या यह है कि इस नए सरणी बनाए रखा नहीं है,

मुझे लगता है कि होगा वर्ष सरणी चला गया हो जाएगा ... और नई सरणी में इस्तेमाल किया जा सकता है। (लेकिन मुझे लगता है नहीं।)

आगे, आपके पास मेमोरी रिसाव है क्योंकि आपने कभी भी मूल सरणी को मुक्त नहीं किया है।

मैं सोच रहा था कि पुरानी सरणी को मुक्त करने का अनुमान नहीं था ... मैं इसके साथ नहीं कर रहा हूं ... मैं बस इसे अपने नए मूल्यों को बदलने के लिए बदलना चाहता हूं। (लेकिन मुझे लगता है नहीं।)

लेकिन एक [anArray रिलीज] का उपयोग करना है;

मैं सोच रहा था कि मुझे आवंटित स्मृति को रिलीज़ करने का कारण होगा ... (लेकिन मुझे लगता है) ... और फिर मुझे और अधिक स्मृति आवंटित करना होगा। (लेकिन मुझे नहीं लगता।)

anArray = [[NSMutableArray arrayWithObjects: @ "एक", @ "दो", @ "तीन", शून्य] बनाए रखने];

तो मुझे इसे "बनाए रखना" है ... तो यह मेरे नीचे से गायब नहीं होता है? (सुनिश्चित नहीं हैं कि क्यों यह जब तक मैं यह करने के लिए ... बता होगा मेरा अंतिम dealloc कॉल में।।)

एक और, शायद और अधिक सही तरीका यह addObject उपयोग करने के लिए किया जाएगा तय करने के लिए: या addObjectsFromArray : लगातार नए सरणी बनाने के बजाय एनएसएमयूटेबलएरे तरीकों।

मैं केवल बनाने के लिए एक सरणी चाहते हैं ... और सिर्फ इसका इस्तेमाल के रूप में मैं चाहता हूँ। मैं कभी भी एडी एरे में नहीं चाहता हूं। मैं इसे अपने नए मूल्यों में सेट करना चाहता हूं।

+0

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

+0

मेरी इच्छा है कि मैं आपको एक से अधिक वोट दे सकता हूं - मुझे वही समस्याएं आ रही हैं - उद्देश्य सी काउंटर सहज से परे है। – Jimmery

उत्तर

11

आप

anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; 

इसके बजाय के साथ अपने सरणी लोड हो रहा है नहीं कर रहे हैं, तो आप एक नया उदाहरण इसकी जगह जाता है, और भी बदतर: एक उदाहरण है, जिसका संदर्भ वास्तव में कुछ इकाई आप नियंत्रित नहीं करते के स्वामित्व में है के साथ (सबसे संभावना है, एक NSAutoreleasePool।) संदर्भ आप ठीक ढंग से स्वामित्व, एक के बाद

[[NSMutableArray alloc] init] 

बनाई खो दिया है और लीक कर दिया जाएगा। पूरे सरणी संदर्भ की जगह की

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

[anArray addObject: @"one"] 
[anArray addObject: @"two"] 

आदि आदेश पुराने मूल्यों को साफ करने के लिए उत्परिवर्तित, विधि removeAllObject काम हो सकता है । उत्परिवर्तन विधियां भी हैं, जिनका उपयोग कई मानों को एक साथ में जोड़ने के लिए किया जा सकता है।

वैकल्पिक रूप से, आप पहले से उपयोग की जाने वाली निर्माण विधि का उपयोग करके सरणी आवंटित कर सकते हैं, लेकिन इसे बनाए रखने के लिए सावधान रहें। viewDidLoad में

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain]; 
alloc/ init अनुक्रम के बजाय

है।

यदि आप वास्तव में संपूर्ण सरणी को प्रतिस्थापित करना चाहते हैं, तो आप मैन्युअल रूप से संदर्भ गणना करने के बजाय properties का उपयोग करने पर विचार करना चाहेंगे।

4

समस्या anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; यह आपके द्वारा प्रारंभ में बनाए गए सरणी को प्रतिस्थापित करता है। ऐसा करने में समस्या यह है कि यह नई सरणी बरकरार नहीं है, इसलिए जैसे ही विधि वापस आती है, आप इसे खो देते हैं। इसके अलावा, आपके पास मेमोरी रिसाव है क्योंकि आपने मूल सरणी को कभी भी मुक्त नहीं किया है।

इसे ठीक करने के कई तरीके हैं, लेकिन इसके बजाय [anArray release]; anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain]; का उपयोग करना है।

इसे ठीक करने के लिए एक और, शायद अधिक सही तरीका addObject: या addObjectsFromArray:NSMutableArray विधियों को लगातार नए सरणी बनाने के बजाय उपयोग करना होगा।

3

इस सरल मेमोरी नियम को याद रखें: केवल के ऑब्जेक्ट्स को रिलीज़ करें। आपके पास अपने द्वारा वस्तुओं केवल आप का उपयोग कर उन्हें बनाते समय:

  • init(इस विधि 1 की गिनती को बनाए रखने के साथ एक नई वस्तु बनाता है)
  • new(इस विधि का उपयोग कर alloc और रूप में ही है init)
  • copy
  • retain (इस विधि 1 की गिनती को बनाए रखने के साथ और विधि के रिसीवर की सामग्री के साथ एक नई वस्तु बनाता है) dealloc आटेस स्वचालित रूप से

प्रणाली (इस विधि 1 के साथ बनाए रखने गिनती बढ़ जाती है) शून्य की गिनती को बनाए रखने के साथ वस्तुओं। आपको release आपके द्वारा किए जाने वाले प्रत्येक ऑब्जेक्ट के बाद आपके पास है। यदि आप बहुत जल्द release हैं, तो आपको एक खतरनाक स्थिति मिलती है। यदि आप release नहीं करते हैं तो जब आप इसके साथ काम करते हैं, तो आपको एक रिसाव मिलती है।

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

string = [[NSString alloc] init]; 

string अब एक की गिनती है। लेकिन क्योंकि NSString एक अपरिवर्तनीय वस्तु है, इसे प्रारंभ करने के बाद बदला नहीं जा सकता है। string असाइन करने का एक तरीका यह मानना ​​प्रारंभ करते समय इसे कर रहा है।

string = [[NSString alloc] initWithString: @"Hello, World!"]; 

आप string नियमित रूप से बदलने की जरूरत है, तो आप एक और वर्ग है कि परिवर्तनशील है का उपयोग कर सकते हैं: NSMutableString। लेकिन फिर भी, उन्हें बदलने का एकमात्र तरीका एक संदेश में है।

string = [[NSMutableString alloc] initWithString: @"Initial string"]; 
[string setString: @"Modified string"]; 

बस ध्यान दें, इस निम्नलिखित कोड है एक स्मृति रिसाव में गलत और परिणाम।

string = [[NSMutableString alloc] initWithString: @"Initial string"]; 
string = @"Modified string"; 

पहली पंक्ति में, string एक नव निर्मित वस्तु को सौंपा गया है। दूसरे में, string को दूसरी स्ट्रिंग में असाइन किया गया है। आप नव निर्मित ऑब्जेक्ट का संदर्भ खो देते हैं और आपको रिसाव मिलती है: आप उस ऑब्जेक्ट को रिलीज़ नहीं कर सकते जिसके बारे में आपका कोई संदर्भ नहीं है।

जब आप इसे पूर्णांक (int प्रकार) के साथ करते हैं तो आपको कोई समस्या नहीं होती है, क्योंकि यह एक "मूल" वस्तु है। उद्देश्य-सी रनटाइम उन डेटा प्रकारों को सीधे उनके मूल्य के साथ जोड़ता है, न कि सूचक।

int1 = 4; 
int1 = 5; 

नोट 1. भूलना हमेशा क्रम अपने सूचक है कि किस प्रकार बताने के लिए न करें। यदि आप string का उपयोग करना चाहते हैं, तो आपको इसे अपने शीर्षलेख में (यदि यह सार्वजनिक है) या कार्यान्वयन (यदि आप इसे अन्य तरीकों से छिपाएं) में परिभाषित करना चाहते हैं। फिर आप स्वतंत्र रूप से नाम का उपयोग कर सकते हैं।

NSString *string; 

स्टार रनटाइम को बताता है कि यह एक सूचक है। देशी प्रकारों के लिए, कोई सूचक नहीं है, इसलिए आपको यह मिलता है।

int int1; 

नोट 2. सरणी (और शब्दकोशों, आदि) से व्यवहार करते हैं कि सभी में NSString तरह वे दोनों अपरिवर्तनीय और परिवर्तनशील विविधताएं हैं।

नोट 3. अधिकांश वर्गों में विशेष विधियां होती हैं जो सभी को आवंटित, प्रारंभिक और स्वचालित रूप से एक साथ रखती हैं।

NSArray *myArray = [NSArray arrayWithObjects: @"Butter", @"Milk", @"Honey", nil]; 

एक autoreleased वस्तु मैनुअल release की जरूरत नहीं है के रूप में सिस्टम कुछ समय बाद आप के लिए यह release होगा। यह परिस्थितियों में बहुत आसान है जहां आपको केवल विधि की अवधि या विधियों के बीच किसी ऑब्जेक्ट की आवश्यकता होती है, न कि ऑब्जेक्ट का स्थायी भाग। जब आप autorelease मुख्य थ्रेड (एक जीयूआई के साथ एक ऐप में) पर कुछ ऑब्जेक्ट करते हैं, तो यह release डी होगा जब ईवेंट लूप वर्तमान लूप को समाप्त करता है (यह कुछ ईवेंट संसाधित होने पर समाप्त होता है)। ऐप्पल के दस्तावेज़ों में Autorelease पूल के बारे में और पढ़ें।

मुझे आशा है कि मैं उन सभी की मदद करूंगा जो अच्छी तरह समझ में नहीं आते हैं। जब तक मैंने भारी प्रयोग नहीं किया, तब तक मुझे कुछ महीनों तक समस्याएं थीं। :-)

+0

क्या आपको सरणी में सभी तत्वों के माध्यम से लूप करने की आवश्यकता है और प्रत्येक पर रिलीज को कॉल करें? – tivo

+0

@tivo यदि आप एआरसी (जो एक्सकोड में डिफ़ॉल्ट है) का उपयोग कर रहे हैं, तो आप कभी भी 'रिलीज़' का उपयोग कभी नहीं करते हैं। ;-) –

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