2009-08-18 13 views
6

का उपयोग किए बिना एक उद्देश्य-सी वर्ग संपत्ति सेट करना आज सुबह मैं एक आईफोन ऐप में एक दुर्घटना में भाग गया जिस पर मैं काम कर रहा हूं और जब मैंने बग तय किया है, तो मैं सिंटैक्टिक कारण के बारे में उत्सुक हूं क्योंकि यह एक समस्या थी।एक स्व-संदर्भ

मेरा कोड सरल तत्वों में कम हो गया है। मैं आइटम्स के लिए एनएसएआरएआरई का उपयोग कर टेबलव्यू में आइटम पॉप्युलेट कर रहा हूं।

@interface FooViewController : UITableViewController { 
    NSArray *stuff; 
} 

@property (nonatomic, retain) NSArray *stuff; 

और मेरे कार्यान्वयन फ़ाइल में: NSArray एक संपत्ति है

@synthesize stuff; 

- (void)viewDidLoad {  
    NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    self.stuff = arr; 

    [arr release]; 
} 

अब, जब मैं पहली विधि लिखा था, मैं गलती से बंद "आत्म।" छोड़ और यह बम का कारण बन गया। हालांकि परीक्षण करते समय, यह पहली बार ब्लश पर काम करता था। मैंने कोशिश की थी:

stuff = arr; 
NSLog(@"%d", [stuff count]); 

लेकिन बमबारी की अन्य विधियों में सामान का उपयोग कर। अब जब मैंने समस्या तय की है, तो मैं अन्य स्थानों पर [सामान गिनती] का उपयोग कर सकता हूं।

तो क्यों मैं कुछ स्थानों में सामान उपयोग कर सकते हैं, लेकिन दूसरों में मैं self.stuff का उपयोग करना चाहिए?

उत्तर

4

यह भी ठीक से काम किया है जाएगा:

- (void)viewDidLoad {  
    stuff = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
} 

क्योंकि सरणी alloc द्वारा बनाए रखा गया था।लेकिन यह अगर आप एक संपत्ति है डॉट नोटेशन से चिपके और autorelease सरणी निर्माण के तरीकों, जहां पाने के उपयोग करने के लिए आम तौर पर बेहतर है "मुक्त करने के लिए" को बरकरार रखे हुए संपत्ति से:

- (void)viewDidLoad {  
    NSArray *arr = [NSArray arrayWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    self.stuff = arr; 

} 

आप शायद बस इसे छोड़ दिया बाहर रखने के लिए चीजों को सरल है, लेकिन आप भी dealloc में इस सरणी रिक्त करने की आवश्यकता:

- (void)dealloc {  
    [stuff release]; stuff = nil; 
} 
+1

यदि आप गुणों का उपयोग करने जा रहे हैं, तो आपको उन्हें हर जगह उपयोग करना चाहिए, यानी डेलोक सामग्री को आसानी से पढ़ना चाहिए: self.stuff = nil; गलतियों से बचने में मदद करने के लिए एक आम तरीका उदाहरण चर को घोषित करना है: NSArray * _stuff; संपत्ति घोषणा एक ही है, लेकिन संश्लेषण कथन अब इस तरह दिखना चाहिए: @ सिंथेसाइज सामान = _stuff; अब जब भी आप स्वयं के बिना सामान का उपयोग करने का प्रयास करते हैं तो संकलक एक त्रुटि को ध्वजांकित करेगा। –

+1

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

+0

टिप के लिए धन्यवाद। मुझे आश्चर्य है कि यह कितना प्रासंगिक हो रहा है, खासकर जब से कोई * केवीओ ट्रिगर नहीं कर सकता है? उल्लेख नहीं है कि आधुनिक रनटाइम में हम * संश्लेषित उदाहरण चर के साथ एक्सेसर्स का उपयोग करेंगे *। मुझे लगता है कि ऐप्पल यह सुनिश्चित कर रहा है कि उनका कोड इस तरह की चीजों के खिलाफ सुरक्षा करता है। अब तक मैंने अपने कोड के साथ किसी भी समस्या में भाग नहीं लिया है, लेकिन अब मैं देख रहा हूं कि मुझे चेतावनी दी गई है :-) –

3

stuff = ... सीधे संपत्ति के बैकिंग फ़ील्ड का संदर्भ देता है। यह बरकरार गिनती में वृद्धि नहीं करता है। नतीजतन, ऑब्जेक्ट को कहीं और जारी करने से इसकी गिनती गिनती शून्य हो सकती है और जब भी आप इसका संदर्भ रखते हैं तो इसे हटा दिया जाता है। इसके अलावा, यह संपत्ति के पिछले मूल्य के लिए स्मृति रिसाव का कारण बन सकता है।
ऐसा लगता है कि यह कभी-कभी काम करने जैसा लगता है कि ऑब्जेक्ट शायद किसी और द्वारा, अभी तक नहीं हटाया गया है।

दूसरी तरफ, self.stuff = ... संपत्ति के सेट एक्सेसर को एक संदेश भेजेगा जो गिनती को बनाए रखने का ख्याल रखेगा।

5

जब आप (स्वयं) और डॉट सिंटैक्स का उपयोग करते हैं, जिस तरह से आपने संपत्ति को परिभाषित किया है (nonatomic, retain), एनएसएआरएआरई (सामान) को बरकरार रखा जाता है।

जब आप नहीं करते हैं, तो आप अभी भी असाइनमेंट कर रहे हैं, लेकिन आप एलोक + इनिट के माध्यम से अंतर्निहित धारणा से अलग सरणी को बरकरार नहीं रखते हैं - और आप इसे तुरंत रिलीज़ करते हैं।

आप के माध्यम से "self.stuff = आगमन" बताए करके आसपास पहुंच सकते हैं:

stuff = [arr retain]; 

लेकिन जब से तुम एक संपत्ति परिभाषित है, तो आप स्पष्ट रूप से डॉट सिंटैक्स का उपयोग और आप के लिए कहा जाता है बना रहेगा होने होना चाहता हूँ।

3

कर के बीच अंतर:

stuff=arr; 

और

self.stuff=arr; 

यह है कि दूसरे मामले में, आप वास्तव में स्वचालित रूप से स्वचालित रूप से संश्लेषित सेटस्टफ को कॉल कर रहे हैं: एक्सेसर विधि, जो सरणी को बरकरार रखती है। आपके द्वारा पोस्ट किए गए कोड में, सरणी को alloc/initWithObjects के साथ बनाया जा रहा है, इसलिए इसमें पहले से ही 1

है, आपको बस अपने दृश्य में कॉल को [एआर रिलीज़] में हटाने की आवश्यकता हैडिडलोड: विधि , और सब कुछ ठीक हो जाएगा:

- (void)viewDidLoad {  
    NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    stuff = arr; 
} 

आपने देखा के रूप में, आप भी "ठीक" कर सकते हैं इस self.stuff का उपयोग करके। मैं ऐसा करने के खिलाफ अनुशंसा करता हूं, क्योंकि यह कोड के अर्थ को अस्पष्ट करता है, और अतिरिक्त मामलों को जोड़ता है जो ज्यादातर मामलों में आवश्यक नहीं है। आम तौर पर, मैं "स्वयं" का उपयोग न करने की अनुशंसा करता हूं। आपके उदाहरण विधियों में वाक्यविन्यास।

+0

तो, अगर @property ने 'असाइनमेंट' असाइन किया है, तो पहुंच के सामने 'self.' का उपयोग नहीं करना ठीक है? – bobobobo

+0

सामान्य रूप से, हां। जैसा कि अन्य उत्तरों में बताया गया है, प्रत्यक्ष संपत्ति पहुंच करने से केवीओ पर्यवेक्षकों को आग नहीं मिलेगी, या तो (जो वांछनीय हो सकता है या नहीं)। –

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