ऑब्जेक्टिव-सी और कोको लिखते समय आपके द्वारा उपयोग की जाने वाली सर्वोत्तम प्रथाएं क्या हैं? [बन्द है]


346

मुझे एचआईजी के बारे में पता है (जो काफी काम का है!), लेकिन ऑब्जेक्टिव-सी लिखते समय आप किन प्रोग्रामिंग प्रथाओं का उपयोग करते हैं, और विशेष रूप से कोको (या कोकोआटच) का उपयोग करते समय।


इस ब्लॉग पोस्ट को देखें, बहुत अच्छा। ironwolf.dangerousgames.com/blog/archives/913
user392412

जवाबों:


398

कुछ चीजें हैं जो मैंने करना शुरू कर दिया है, मुझे नहीं लगता कि मानक हैं:

1) गुणों के आगमन के साथ, मैं अब "निजी" वर्ग चर को उपसर्ग करने के लिए "_" का उपयोग नहीं करता हूं। आखिरकार, अगर एक चर को अन्य वर्गों द्वारा एक्सेस किया जा सकता है, तो क्या इसके लिए कोई संपत्ति नहीं होनी चाहिए? मैंने हमेशा "_" उपसर्ग को कोड बदसूरत बनाने के लिए नापसंद किया, और अब मैं इसे छोड़ सकता हूं।

2) निजी चीजों की बात करें, तो मैं एक वर्ग विस्तार में .m फ़ाइल के भीतर निजी पद्धति की परिभाषाएँ देना पसंद करता हूँ:

#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

बाहरी लोगों के साथ .h फ़ाइल की अव्यवस्था क्यों परवाह नहीं करनी चाहिए? खाली () .m फ़ाइल में निजी श्रेणियों के लिए काम करता है, और यदि आप घोषित तरीकों को लागू नहीं करते हैं तो चेतावनी जारी करते हैं।

3) मैंने @synthesize निर्देशों के ठीक नीचे .m फ़ाइल के शीर्ष पर Dealloc लगाने के लिए लिया है। क्या आपको उन चीजों की सूची में शीर्ष पर नहीं होना चाहिए जो आप कक्षा में सोचना चाहते हैं? यह iPhone जैसे वातावरण में विशेष रूप से सच है।

3.5) तालिका कोशिकाओं में, प्रदर्शन के लिए प्रत्येक तत्व (सेल स्वयं सहित) अपारदर्शी बनाते हैं। इसका मतलब है कि हर चीज में उपयुक्त बैकग्राउंड कलर सेट करना।

3.6) NSURLConnection का उपयोग करते समय, एक नियम के रूप में आप प्रतिनिधि पद्धति को लागू करना चाहते हैं:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

मुझे लगता है कि अधिकांश वेब कॉल बहुत विलक्षण हैं और यह उस नियम से अधिक अपवाद है, जिसे आप खासतौर पर वेब सेवा कॉल के लिए प्रतिसाद दे रहे हैं। दिखाए गए तरीके को लागू करना प्रतिक्रियाओं के कैशिंग को अक्षम करता है।

रुचि के अलावा, जोसेफ मैटिएलो (iPhone मेलिंग सूची में प्राप्त) से कुछ अच्छे iPhone विशिष्ट सुझाव हैं। वहाँ अधिक हैं, लेकिन ये सबसे आम तौर पर मुझे लगा कि उपयोगी थे (ध्यान दें कि कुछ बिट्स अब मूल से थोड़ा संपादित किए गए हैं ताकि प्रतिक्रियाओं में शामिल विवरणों को शामिल किया जा सके):

4) यदि आपको कोरलोकेशन के साथ काम करना हो तो केवल डबल प्रिसिजन का उपयोग करें। यह सुनिश्चित करें कि आप अपने स्थिरांक को 'f' में समाप्त करते हैं ताकि gcc को फ्लोट के रूप में संग्रहीत किया जा सके।

float val = someFloat * 2.2f;

यह ज्यादातर महत्वपूर्ण है जब someFloatवास्तव में एक डबल हो सकता है, आपको मिश्रित-मोड गणित की आवश्यकता नहीं है, क्योंकि आप भंडारण पर 'वैल' में सटीक खो रहे हैं। जबकि फ्लोटिंग-पॉइंट नंबर iPhones पर हार्डवेयर में समर्थित हैं, फिर भी एकल परिशुद्धता के विपरीत डबल-सटीक अंकगणित करने में अधिक समय लग सकता है। संदर्भ:

माना जाता है कि पुराने फोन एक ही गति से काम करते हैं, लेकिन आप डबल्स की तुलना में रजिस्टरों में अधिक एकल सटीक घटक रख सकते हैं, इसलिए कई गणनाओं के लिए एकल परिशुद्धता तेजी से समाप्त हो जाएगी।

5) अपने गुण सेट करें nonatomic। वे atomicडिफ़ॉल्ट रूप से और संश्लेषण पर, मल्टी-थ्रेडिंग समस्याओं को रोकने के लिए सेमाफोर कोड बनाया जाएगा। आप में से 99% को शायद इस बारे में चिंता करने की आवश्यकता नहीं है और कोड गैर-परमाणु पर सेट होने पर बहुत कम फूला हुआ और अधिक स्मृति-कुशल है।

6) SQLite बड़े डेटा सेट को कैश करने का एक बहुत तेज़ तरीका हो सकता है। उदाहरण के लिए एक मानचित्र एप्लिकेशन अपनी टाइलों को SQLite फ़ाइलों में कैश कर सकता है। सबसे महंगा हिस्सा डिस्क I / O है। बड़े ब्लॉकों को भेजकर BEGIN;और उनके COMMIT;बीच कई छोटे लेखन से बचें । हम प्रत्येक नए सबमिट पर रीसेट करने वाले उदाहरण के लिए 2 सेकंड के टाइमर का उपयोग करते हैं। जब यह समाप्त हो जाता है, तो हम COMMIT भेजते हैं; , जो आपके सभी लेखन को एक बड़े हिस्से में जाने का कारण बनता है। SQLite लेन-देन के डेटा को डिस्क में संग्रहीत करता है और यह आरंभ / समाप्ति रैपिंग कई लेनदेन फ़ाइलों के निर्माण से बचती है, सभी लेनदेन को एक फ़ाइल में समूहीकृत करता है।

इसके अलावा, SQL आपके GUI को ब्लॉक कर देगा यदि यह आपके मुख्य धागे पर है। यदि आपके पास बहुत लंबी क्वेरी है, तो अपने प्रश्नों को स्थिर वस्तुओं के रूप में संग्रहीत करना और अपनी SQL को एक अलग थ्रेड पर चलाना एक अच्छा विचार है। @synchronize() {}ब्लॉक में क्वेरी स्ट्रिंग के लिए डेटाबेस को संशोधित करने वाली किसी भी चीज़ को लपेटना सुनिश्चित करें । लघु प्रश्नों के लिए सिर्फ आसान सुविधा के लिए मुख्य थ्रेड पर चीजों को छोड़ दें।

अधिक SQLite अनुकूलन युक्तियां यहां हैं, हालांकि दस्तावेज़ पुराना दिखाई देता है, जिनमें से कई बिंदु अभी भी अच्छे हैं;

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html


3
डबल अंकगणित के बारे में अच्छी टिप-ऑफ।
एडम अर्न्स्ट

8
क्लास एक्सटेंशन अब निजी तरीकों के लिए पसंदीदा तरीका है: developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/…
Casebash

9
IPhone पर डबल्स के बारे में आपकी सलाह तारीख से बाहर है stackoverflow.com/questions/1622729/…
Casebash

3
तारीख से बाहर नहीं; पूरी तरह से गलत: मूल iPhone ने लगभग समान गति से हार्डवेयर में फ्लोट और डबल्स का समर्थन किया। SQLite भी स्मृति में लेनदेन नहीं रखता है; वे डिस्क पर जर्नल कर रहे हैं। केवल लंबी क्वेरी आपके UI को अवरुद्ध करती हैं; मुख्य थ्रेड में सब कुछ चलाने और तेज़ क्वेरी का उपयोग करने के लिए यह कम गन्दा है।
टीसी

1
@tc: मैंने लेन-देन के बारे में SQL आइटम को ठीक किया, ध्यान दें कि मैंने स्वयं उन चार या अंतिम वस्तुओं को नहीं लिखा था। मैंने यह भी स्पष्ट किया कि पृष्ठभूमि के चलते प्रश्नों के बारे में केवल बहुत लंबे प्रश्नों के लिए था (कभी-कभी आप उन्हें छोटा नहीं कर सकते)। लेकिन कुछ बिंदुओं के कारण पूरी बात को "गलत" कहना मुझे लगता है कि मैं चरम पर हूं। इसके अलावा, ऊपर दिए गए उत्तर पहले से ही कहा गया है: "पुराने फोन पर माना जाता है कि गणना समान गति से चल रही है" लेकिन एकल परिशुद्धता रजिस्टरों की अधिक संख्या के बारे में भाग पर ध्यान दें जो उन्हें अभी भी बेहतर बना रहे हैं।
केंडल हेल्मसटेटर गेलनर

109

प्रारूप के तार के रूप में अज्ञात तारों का उपयोग न करें

जब तरीके या फ़ंक्शंस एक प्रारूप स्ट्रिंग तर्क लेते हैं, तो आपको यह सुनिश्चित करना चाहिए कि प्रारूप स्ट्रिंग की सामग्री पर आपका नियंत्रण है।

उदाहरण के लिए, स्ट्रिंग्स को लॉग करते समय, यह स्ट्रिंग चर को एकमात्र तर्क के रूप में पास करने के लिए लुभाता है NSLog:

    NSString *aString = // get a string from somewhere;
    NSLog(aString);

इसके साथ समस्या यह है कि स्ट्रिंग में ऐसे अक्षर हो सकते हैं जिन्हें प्रारूप स्ट्रिंग के रूप में व्याख्या किया जाता है। इससे गलत आउटपुट, क्रैश और सुरक्षा समस्याएं हो सकती हैं। इसके बजाय, आपको स्ट्रिंग चर को प्रारूप स्ट्रिंग में स्थान देना चाहिए:

    NSLog(@"%@", aString);

4
मैं इससे पहले एक बार काट चुका हूं।
एडम अर्न्स्ट

यह किसी भी प्रोग्रामिंग भाषा के लिए अच्छी सलाह है
टॉम फोबियर

107

मानक कोको नामकरण और स्वरूपण सम्मेलनों और शब्दावली का उपयोग करें जो आप किसी अन्य वातावरण से उपयोग किए जाते हैं। वहाँ कोको डेवलपर्स के बहुत सारे हैं , और जब उनमें से एक आपके कोड के साथ काम करना शुरू कर देता है, तो यह अन्य कोको कोड के समान दिखता है और लगता है तो यह बहुत अधिक स्वीकार्य होगा।

क्या करना है और क्या नहीं इसके उदाहरण हैं:

  • id m_something;किसी ऑब्जेक्ट के इंटरफ़ेस में घोषित न करें और इसे एक सदस्य चर या फ़ील्ड कहें ; उपयोग somethingया _somethingइसके नाम के लिए और इसे एक उदाहरण चर कहते हैं
  • एक गेट्टर का नाम मत लो -getSomething; उचित कोको नाम सिर्फ है -something
  • एक सेटर का नाम न लें -something:; यह होना चाहिए-setSomething:
  • विधि का नाम तर्कों के साथ मिलाया गया है और इसमें कॉलोन शामिल हैं; यह -[NSObject performSelector:withObject:]नहीं है NSObject::performSelector
  • अंडरबर्स (अंडरस्कोर) के बजाय विधि के नाम, पैरामीटर, चर, वर्ग के नाम आदि में इंटर-कैप (कैमलकेज़) का उपयोग करें।
  • क्लास के नाम ऊपरी मामले के अक्षर, चर और विधि के नाम के साथ शुरू होते हैं।

जो कुछ भी आप करते हैं, Win16 / Win32 शैली हंगेरियन संकेतन का उपयोग करें। यहां तक ​​कि Microsoft ने .NET प्लेटफ़ॉर्म की ओर कदम बढ़ाया।


5
मेरा तर्क है, सेटसमैट का उपयोग न करें: / कुछ बिल्कुल - इसके बजाय गुणों का उपयोग करें। इस बिंदु पर कुछ ही लोग हैं जिन्हें वास्तव में टाइगर (केवल गुणों का उपयोग न करने का एकमात्र कारण) को लक्षित करने की आवश्यकता है
केंडल हेल्मेस्सेट्टर गेलर

18
गुण अभी भी आपके लिए एक्सेसर तरीके उत्पन्न करते हैं, और प्रापक पर गुणक = / सेटर = विशेषताएँ आपको विधियों के नाम निर्दिष्ट करने देती हैं। इसके अलावा, आप गुणों के साथ foo.something सिंटैक्स के बजाय [foo something] सिंटैक्स का उपयोग कर सकते हैं। इसलिए एक्सेसर नामकरण अभी भी प्रासंगिक है।
क्रिस हैनसन

3
यह C ++ से आने वाले किसी व्यक्ति के लिए एक महान संदर्भ है, जहां मैंने आपके खिलाफ सलाह देने वाली अधिकांश चीजें कीं।
क्लिंटन ब्लैकमोर

4
एक सेटर को डेटाबेस में कुछ सहेजने का कारण नहीं होना चाहिए। एक कारण है कि कोर डाटा में एक -save है: NSManagedObjectContext पर विधि, बजाय बसने वालों ने तत्काल अपडेट उत्पन्न किया है।
क्रिस हैनसन

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

106

IBOutlets

ऐतिहासिक रूप से, आउटलेट का मेमोरी प्रबंधन खराब रहा है। वर्तमान सर्वोत्तम प्रथा को आउटलेट्स को गुणों के रूप में घोषित करना है:

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

गुणों का उपयोग करने से स्मृति प्रबंधन शब्दार्थ स्पष्ट हो जाता है; यदि आप उदाहरण चर संश्लेषण का उपयोग करते हैं तो यह एक सुसंगत पैटर्न भी प्रदान करता है।


1
निब की लोडिंग इसे दो बार बरकरार नहीं रखेगी? (एक बार निब में, संपत्ति के लिए असाइनमेंट द्वारा दूसरा)। क्या मैं डीललोक में उन लोगों को रिहा करने वाला हूं?
कोर्नेल

6
आपको आउटलेट्स को व्यूडायडलोड (iPhone OS 3.0+) या कस्टम सेट व्यू: लीक से बचने के लिए विधि से शून्य करना होगा। जाहिर है आपको डीललॉक में भी रिलीज करना चाहिए।
फ्रैंक ज़्गबग्गा

2
ध्यान रखें कि हर कोई इस शैली से सहमत नहीं है: weblog.bignerdranch.com/?p=95
माइकल

इस तरह से Apple चीजों को भी करता है। "IPhone 3 विकास की शुरुआत" पिछले संस्करणों से भी इस बदलाव का उल्लेख करता है।
१ust

मैंने एक अन्य टिप्पणी में इसका उल्लेख किया है, लेकिन इसे यहां रखा जाना चाहिए: एक बार जब गतिशील आइवर का संश्लेषण आईओएस एप्लिकेशन (यदि / जब?) के लिए शुरू होता है, तो आपको खुशी होगी कि आप संपत्ति बनाम आइवर पर IBOutlet डाल देंगे!
जो डी 'एंड्रिया

97

LLVM / Clang Static विश्लेषक का उपयोग करें

नोट: Xcode 4 के तहत यह अब IDE में बनाया गया है।

आप मैक ओएस एक्स 10.5 पर क्लैंग स्टेटिक एनालाइज़र से - बिना - - अपने सी और ऑब्जेक्टिव-सी कोड (अभी तक कोई सी ++) का विश्लेषण नहीं करते हैं। यह स्थापित करने और उपयोग करने के लिए तुच्छ है:

  1. इस पृष्ठ से नवीनतम संस्करण डाउनलोड करें ।
  2. कमांड-लाइन से, cdआपकी परियोजना निर्देशिका तक।
  3. निष्पादित करें scan-build -k -V xcodebuild

(कुछ अतिरिक्त बाधाएं हैं आदि, विशेष रूप से आपको इसके "डिबग" कॉन्फ़िगरेशन में एक परियोजना का विश्लेषण करना चाहिए - विवरण के लिए http://clang.llvm.org/StaticAnalysisUsage.html देखें - लेकिन यह अधिक-या-कम है यह क्या उबलता है।)

विश्लेषक तब आपके लिए वेब पेजों का एक सेट तैयार करता है, जो संभावित मेमोरी प्रबंधन और अन्य बुनियादी समस्याओं को दर्शाता है जो कंपाइलर का पता लगाने में असमर्थ है।


1
: मैं कुछ परेशानी काम करने के लिए इस हो रही जब तक मैं इन निर्देशों का पालन किया था oiledmachine.com/posts/2009/01/06/...
bbrown

15
स्नो लेपर्ड पर XCode 3.2.1 में, यह पहले से ही बनाया गया है। आप रन -> बिल्ड और एनालिसिस का उपयोग करके या तो इसे मैन्युअल रूप से चला सकते हैं , या आप इसे "रन स्टेटिक एनालाइज़र" बिल्ड सेटिंग के माध्यम से सभी बिल्ड के लिए सक्षम कर सकते हैं। ध्यान दें कि यह उपकरण वर्तमान में केवल C और उद्देश्य-C का समर्थन करता है, लेकिन C ++ / Objective-C ++ का नहीं।
oefe

94

यह सूक्ष्म है, लेकिन एक काम है। यदि आप स्वयं को किसी अन्य ऑब्जेक्ट के प्रतिनिधि के रूप में पास कर रहे हैं, तो उस ऑब्जेक्ट के प्रतिनिधि को आपके सामने रीसेट करें dealloc

- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}

ऐसा करने से आप सुनिश्चित कर रहे हैं कि कोई और प्रतिनिधि विधियाँ नहीं भेजी जाएँगी। जैसा कि आप के बारे में है deallocऔर ईथर में गायब हो जाते हैं आप यह सुनिश्चित करना चाहते हैं कि कुछ भी दुर्घटना से आपको कोई संदेश नहीं भेज सकता है। स्वयं को याद रखें। किसी अन्य वस्तु के द्वारा (यह एक सिंगलटन हो सकता है या ऑटोरेलिज़ पूल या जो भी हो) को बनाए रखा जा सकता है और जब तक आप यह नहीं बताते हैं कि "मुझे संदेश भेजना बंद करो!", यह आपके न्यायसंगत व्यवहार के बारे में सोचता है। उचित खेल है।

इस आदत में शामिल होने से आपको बहुत सारी अजीब दुर्घटनाओं से बचाया जा सकता है जो डीबग करने के लिए एक दर्द हैं।

मुख्य मूल्य मुख्य मूल्य अवलोकन पर लागू होता है, और NSNotifications भी।

संपादित करें:

और भी अधिक रक्षात्मक, परिवर्तन:

self.someObject.delegate = NULL;

में:

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;

8
इस बारे में कुछ भी सूक्ष्म नहीं है, प्रलेखन स्पष्ट रूप से कहता है कि आपको ऐसा करने की आवश्यकता है। प्रेषक Memory Management Programming Guide for Cocoa: Additional cases of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates.
जौने

NULL के बजाय nil का उपयोग करना बेहतर है, क्योंकि NULL मेमोरी को खाली नहीं करेगा।
नवीन शान

@NaveenShan nil == NULL। वे वास्तव में एक ही हैं सिवाय इसके कि nilएक है idऔर NULLएक है void *। आपका कथन सत्य नहीं है।

@TP yep, nil == NULL, लेकिन nil का उपयोग स्पष्ट रूप से पसंदीदा तरीका है, यदि आप सेब उदाहरण कोड टुकड़े के माध्यम से देखते हैं, तो वे हर जगह nil का उपयोग कर रहे हैं, और जैसा कि आपने कहा, nil एक आईडी है, जो इसे शून्य से अधिक पसंद करता है * , ऐसे मामलों में जहां आप आईडी भेजते हैं, वह है।
आहती

1
@Ahti बिल्कुल, और Nil(अपरकेस) प्रकार का है Class*। भले ही वे सभी समान हों, गलत का उपयोग करने से विशेष रूप से वस्तुनिष्ठ-सी ++ में बुरा छोटे कीड़े हो सकते हैं।

86

@kendell

के बजाय:

@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end

उपयोग:

@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end

ऑब्जेक्टिव-सी 2.0 में नया।

क्लास एक्सटेंशन को Apple के ऑब्जेक्टिव-सी 2.0 संदर्भ में वर्णित किया गया है।

"क्लास एक्सटेंशन आपको प्राथमिक वर्ग @interface ब्लॉक के अलावा अन्य स्थानों में एक वर्ग के लिए अतिरिक्त आवश्यक एपीआई घोषित करने की अनुमति देता है"

इसलिए वे वास्तविक वर्ग का हिस्सा हैं - और वर्ग के अतिरिक्त (निजी) श्रेणी नहीं। सूक्ष्म लेकिन महत्वपूर्ण अंतर।


आप ऐसा कर सकते हैं, लेकिन मैं इसे स्पष्ट रूप से एक "निजी" खंड (कार्यात्मक से अधिक प्रलेखन) के रूप में लेबल करना पसंद करता हूं, हालांकि यह पहले से ही स्पष्ट है कि यह .m फ़ाइल में स्थित है ...
केंडल हेल्मिस्सेटर गेलनर

2
सिवाय वहाँ है निजी श्रेणियों और वर्ग एक्सटेंशन के बीच एक अंतर: संपादित में लिंक देखें: "क्लास एक्सटेंशन आप, प्राथमिक वर्ग @interface ब्लॉक के भीतर अतिरिक्त किसी अन्य स्थान में एक वर्ग के लिए अतिरिक्त आवश्यक एपीआई घोषित करने के लिए जैसा कि निम्न उदाहरण में सचित्र अनुमति देते हैं"।
schwa

मैं मानता हूं कि एक अंतर है जहां संकलक आपको चेतावनी देगा जब आपने सीई विधियों को लागू नहीं किया है - लेकिन मुझे वह पहलू बहुत महत्वपूर्ण नहीं लगता है जब सभी विधियां एक ही फाइल में हों, और सभी निजी हों। मैं अभी भी फॉरवर्ड रेफरेंस ब्लॉक को चिन्हित करने के
मेंटेनेंस

3
मैं (निजी) वास्तव में किसी भी अधिक से अधिक () के रूप में बनाए रखने योग्य नहीं है। यदि आप चिंतित हैं तो टिप्पणियों की एक अच्छी खुराक मदद कर सकती है। लेकिन जाहिर है कि जियो और जीने दो। YMMV आदि
schwa

17
(या कुछ अन्य श्रेणी नाम) के ()बजाय उपयोग करने के लिए एक महत्वपूर्ण लाभ है (Private): आप संपत्तियों को फिर से लिखना के रूप में पढ़ सकते हैं जबकि जनता के लिए वे केवल पठनीय हैं। :)
पास्कल

75

ऑटोरेलिस से बचें

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

इस प्रकार, इसके बजाय:

aVariable = [AClass convenienceMethod];

जहां सक्षम हो, आपको इसके बजाय उपयोग करना चाहिए:

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

जब आप अपनी खुद की विधियाँ लिख रहे होते हैं जो एक नई बनाई गई वस्तु को लौटाते हैं, तो आप कोको के नामकरण कन्वेंशन का फ़ायदा उठाकर रिसीवर को फ़्लैग कर सकते हैं कि इसे "नया" विधि नाम के साथ जोड़कर जारी किया जाना चाहिए।

इस प्रकार, इसके बजाय:

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}

आप लिख सकते हैं:

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

चूंकि विधि का नाम "नए" से शुरू होता है, आपके एपीआई के उपभोक्ताओं को पता है कि वे प्राप्त वस्तु को जारी करने के लिए जिम्मेदार हैं (देखें, उदाहरण के लिए, NSObjectController की newObjectविधि )।

(1) आप अपने स्वयं के स्थानीय ऑटोरेलिज पूल का उपयोग करके नियंत्रण ले सकते हैं। इस पर अधिक जानकारी के लिए, ऑटोरेलिज पूल देखें ।


6
मुझे अपनी लागतों (यानी अधिक मेमोरी लीक बग्स) को ऑटोरिलिज़ आउटवेग का उपयोग नहीं करने के लाभ मिलते हैं । मुख्य धागे पर कोड वैसे भी काफी कम-चलने वाला होना चाहिए (या अन्यथा आप यूआई को फ्रीज कर देंगे) और लंबे समय तक चलने वाले, मेमोरी-इंटेंसिव बैकग्राउंड कोड के लिए, आप हमेशा स्थानीय ऑटोरेलिज पूल में मेमोरी-इंटेंसिव भागों को लपेट सकते हैं।
adib

56
मैं असहमत हूं। जब भी संभव हो आप ऑटोरेल्ड ऑब्जेक्ट का उपयोग करें। यदि वे मेमोरी फ़ुटप्रिंट को बहुत अधिक बढ़ाते हैं, तो आपको दूसरे का उपयोग करना चाहिए NSAutoreleasePool। लेकिन आपके द्वारा पुष्टि किए जाने के बाद ही कि यह वास्तव में एक मुद्दा है। समयपूर्व अनुकूलन और वह सब ...
स्वेन

3
मैं 40 सेकंड से कम समय बिताता हूं। एक दिन टाइप करना [someObject रिलीज़] और एक नई ऑब्जेक्ट को इंस्टेंट करते समय "अतिरिक्त लाइन" पढ़ना, लेकिन मैं एक बार एक ऑटोरेलिज बग खोजने के लिए 17 घंटे से जला था जो केवल विशेष मामलों में दिखाई देगा और कंसोल में कोई सुसंगत त्रुटि नहीं देगा। इसलिए जब मैं उसे कहता हूं तो मैं उससे सहमत हो जाता हूं, जैसे "मुझे लगता है कि ऑटोरेलिज को अपनी लागतों का उपयोग नहीं करने के फायदे मिलते हैं"।
रिकागि

7
मैं स्वेन से सहमत हूं। प्राथमिक लक्ष्य कोड स्पष्टता होना चाहिए और कोडिंग त्रुटियों को कम करना चाहिए, स्मृति अनुकूलन के साथ ही जहां यह आवश्यक है। एक [[[फू आवंटन] init] ऑटोरेलिज़] टाइप करना त्वरित है और आप तुरंत इस नई वस्तु को जारी करने के मुद्दे से निपटते हैं। कोड को पढ़ते समय आपको यह सुनिश्चित करने के लिए कि इसे लीक नहीं किया जा रहा है, जारी करने के लिए चारों ओर शिकार नहीं करना है।
माइक वेलर

3
ऑटोरेल्ड ऑब्जेक्ट्स के जीवनचक्र को पर्याप्त स्तर पर अच्छी तरह से परिभाषित और निर्धारित किया जाता है।
Eonil

69

इनमें से कुछ का उल्लेख पहले ही किया जा चुका है, लेकिन यहां मैं अपने शीर्ष के शीर्ष के बारे में सोच सकता हूं:

  • केवीओ नामकरण नियमों का पालन करें। यहां तक ​​कि अगर आप केवीओ का उपयोग नहीं करते हैं, तो भी मेरे अनुभव में अक्सर यह भविष्य में फायदेमंद होता है। और यदि आप केवीओ या बाइंडिंग का उपयोग कर रहे हैं, तो आपको यह जानने की जरूरत है कि वे जिस तरह से काम करने वाले हैं, वे काम करने वाले हैं। यह न केवल एक्सेसर के तरीकों और उदाहरण के चर को कवर करता है, बल्कि कई रिश्तों, सत्यापन, ऑटो-निर्भर निर्भर कुंजियों, और इसी तरह।
  • निजी तरीकों को एक श्रेणी में रखें। न केवल इंटरफ़ेस, बल्कि कार्यान्वयन भी। निजी और गैर-निजी तरीकों के बीच वैचारिक रूप से कुछ दूरी रखना अच्छा है। मैं अपनी .m फ़ाइल में सब कुछ शामिल करता हूं।
  • बैकग्राउंड थ्रेड विधियों को एक श्रेणी में रखें। ऊपर की तरह। मैंने पाया है कि जब आप मुख्य सूत्र पर क्या सोच रहे हैं और क्या नहीं है, इसके बारे में स्पष्ट वैचारिक अवरोध रखना अच्छा है।
  • का उपयोग करें #pragma mark [section]आमतौर पर मैं अपने तरीकों से समूह, प्रत्येक उपवर्ग के ओवरराइड्स, और किसी भी जानकारी या औपचारिक प्रोटोकॉल। यह एक बहुत आसान करने के लिए मैं क्या देख रहा हूँ कूद करने के लिए बनाता है। एक ही विषय पर, समूह समान विधियाँ (जैसे तालिका दृश्य की प्रतिनिधि विधियाँ) एक साथ होती हैं, बस उन्हें कहीं भी न रखें।
  • उपसर्ग निजी विधियों और _ के साथ ivars। जिस तरह से यह दिखता है मुझे पसंद है, और जब मैं दुर्घटना से संपत्ति का मतलब होता है, तो मैं एक आइवर का उपयोग करने की संभावना कम करता हूं।
  • इनिट और डीललोक में उत्परिवर्ती तरीकों / गुणों का उपयोग न करें। मुझे इसकी वजह से कभी कुछ बुरा नहीं हुआ, लेकिन मैं तर्क देख सकता हूं कि अगर आप कुछ ऐसा करने का तरीका बदलते हैं जो आपकी वस्तु की स्थिति पर निर्भर करता है।
  • गुणों में IBOutlets रखो। मैं वास्तव में सिर्फ यह एक यहाँ पढ़ता हूं, लेकिन मैं इसे शुरू करने जा रहा हूं। किसी भी स्मृति लाभ के बावजूद, यह स्टाइलिस्टिक रूप से (कम से कम मेरे लिए) बेहतर लगता है।
  • कोड लिखने से बचें, जिसकी आपको बिल्कुल आवश्यकता नहीं है। यह वास्तव में बहुत सारी चीजों को कवर करता है, जैसे कि जब #defineभी डेटा की आवश्यकता होती है, तो इसे हर बार छाँटने के बजाय एक सरणी बनाना या एक सरणी को कैशिंग करना होगा। इस बारे में मैं बहुत कुछ कह सकता हूं, लेकिन नीचे की पंक्ति कोड को तब तक नहीं लिखती जब तक आपको इसकी आवश्यकता नहीं होती, या प्रोफाइलर आपको बताता है। यह लंबे समय में चीजों को बनाए रखना आसान बनाता है।
  • जो आप शुरू करते हैं उसे पूरा करें। बहुत सारे अर्ध-समाप्त होने के बाद, बग्गी कोड एक परियोजना को मारने का सबसे तेज़ तरीका है। यदि आपको एक स्टब विधि की आवश्यकता है जो ठीक है, तो बस इसे NSLog( @"stub" )अंदर डालकर इंगित करें , या हालांकि आप चीजों का ट्रैक रखना चाहते हैं।

3
मेरा सुझाव है कि आपको निजी तरीकों को एक कक्षा की निरंतरता में रखना चाहिए। (यानी @interface MyClass () ... @ में आपका .m)
जेसन

3
#PRAGMA के बजाय आप एक टिप्पणी का उपयोग कर सकते हैं // मार्क: [अनुभाग] जो अधिक पोर्टेबल है और पहचान के साथ काम करता है।
19'09

जब तक कोई विशेष वाक्यविन्यास मुझे याद नहीं आ रहा है, // मार्क: Xcode के फ़ंक्शंस ड्रॉप डाउन मेनू में एक लेबल नहीं जोड़ता है, जो वास्तव में इसका उपयोग करने का आधा कारण है।
मार्क शारबोन्यू

6
ड्रॉप डाउन में दिखाने के लिए आपको अपरकेस, "// MARK: ..." का उपयोग करना होगा।
Rhult

3
Finish what you startआपके संबंध में आप // TODO:कोड को पूरा करने के लिए उपयोग कर सकते हैं जो ड्रॉप डाउन में दिखाई देगा।
जुलाब

56

इकाई परीक्षण लिखें। आप कोको में बहुत सी चीजों का परीक्षण कर सकते हैं जो अन्य रूपरेखाओं में कठिन हो सकती हैं। उदाहरण के लिए, यूआई कोड के साथ, आप आम तौर पर यह सत्यापित कर सकते हैं कि चीजें जुड़ी हुई हैं क्योंकि उन्हें होना चाहिए और विश्वास है कि जब वे काम करेंगे। और आप उन्हें परखने के लिए आसानी से राज्य और प्रतिनिधि प्रतिनिधि विधियों की स्थापना कर सकते हैं।

आपके पास अपने आंतरिक के लिए परीक्षण लिखने के तरीके में सार्वजनिक बनाम संरक्षित बनाम निजी पद्धति दृश्यता नहीं है।


आप किस टेस्ट फ्रेमवर्क की सलाह देते हैं?
melfar

13
Xcode में OCUnit, ऑब्जेक्टिव-सी यूनिट टेस्टिंग फ्रेमवर्क शामिल है, और आपकी बिल्ड प्रक्रिया के हिस्से के रूप में यूनिट टेस्ट के बंडलों को चलाने के लिए समर्थन शामिल है।
क्रिस हैनसन

55

गोल्डन रूल: यदि आप allocतो आप release!

अद्यतन: जब तक आप एआरसी का उपयोग नहीं कर रहे हैं


26
इसके अलावा, आप अगर copy, mutableCopy, newया retain
स्वेन

54

Objective-C को ऐसे न लिखें जैसे कि यह Java / C # / C ++ / etc था।

मैंने एक बार देखा कि जावा ईई वेब एप्लिकेशन लिखने के लिए इस्तेमाल की जाने वाली एक टीम ने कोको डेस्कटॉप एप्लिकेशन लिखने की कोशिश की। मानो यह एक जावा ईई वेब अनुप्रयोग था। वहाँ बहुत सारे AbstractFooFactory और FooFactory और IFoo और Foo के चारों ओर उड़ रहा था जब वे वास्तव में जरूरत थी एक Foo वर्ग और संभवतः एक Fooable प्रोटोकॉल था।

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


10
एक जावा डेवलपर के रूप में जिसने ऑब्जेक्टिव-सी में एक अमूर्त फैक्ट्री लिखी है, मुझे यह पेचीदा लगता है। क्या आप थोड़ा और समझाएंगे कि यह कैसे काम करता है - शायद एक उदाहरण के साथ?
टीबॉट

2
क्या आप अभी भी मानते हैं कि आपको इस उत्तर को पोस्ट करने के बाद हर समय के बाद अमूर्त कारखाना वर्गों की आवश्यकता नहीं है?
kirk.burleson

50

सुनिश्चित करें कि आप डिबगिंग मैजिक पेज को बुकमार्क कर लें । कोको बग के स्रोत को खोजने की कोशिश करते समय दीवार के खिलाफ अपना सिर पीटते समय यह आपका पहला पड़ाव होना चाहिए।

उदाहरण के लिए, यह आपको बताएगा कि उस पद्धति को कैसे खोजना है जहां आपने पहले मेमोरी आवंटित की थी जो बाद में क्रैश (जैसे ऐप समाप्ति के दौरान) हो रही है।


1
अब डीबगिंग मैजिक पेज का एक iOS विशिष्ट संस्करण है ।
जेठू

38

इससे बचने का प्रयास करें कि मैंने अब क्या Newbiecategoryaholism को बुलाने का फैसला किया है। जब नवागंतुक उद्देश्य-सी श्रेणियों को खोजते हैं, तो वे अक्सर जंगली हो जाते हैं, अस्तित्व में हर वर्ग के लिए उपयोगी छोटी श्रेणियों को जोड़ते हैं ( "क्या? मैं एक संख्या को रोमन संख्याओं को NSNumber रॉक पर बदलने के लिए जोड़ सकता हूं!" )।

यह मत करो।

आपका कोड अधिक पोर्टेबल और दो दर्जन नींव वर्गों के शीर्ष पर छिड़के गए छोटे श्रेणी के दर्जनों तरीकों के साथ समझने में आसान होगा।

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

अन्य खतरे भी हैं, जब तक कि आप अपनी श्रेणी के तरीकों को नाम नहीं दे रहे हैं (और जो पूरी तरह से पागल ddribin के अलावा है?) वहाँ एक मौका है कि Apple, या एक प्लगइन, या आपके पते की जगह में चल रहे कुछ और भी उसी को परिभाषित करेंगे? एक ही नाम के साथ विधि थोड़ा अलग साइड इफेक्ट के साथ ....

ठीक। अब जब आपको चेतावनी दी गई है, तो "इस भाग को न करें" को अनदेखा करें। लेकिन अत्यधिक संयम बरतें।


मुझे आपका उत्तर पसंद है, मेरी सलाह उपयोगिता कोड को स्टोर करने के लिए एक श्रेणी का उपयोग नहीं करेगी जब तक कि आप एक से अधिक जगह में कुछ कोड को दोहराने के बारे में नहीं होते हैं और कोड स्पष्ट रूप से उस वर्ग से संबंधित होता है जो आप वर्गीकृत करने वाले हैं ...
केंडल

मैं सिर्फ पाइपिंग करना चाहूंगा और श्रेणी विधियों के नामकरण के लिए अपने समर्थन को आवाज दूंगा। यह सिर्फ सही काम करने जैसा लगता है।
माइकल बकले

+1 यदि केवल रोमन अंकों के लिए। मैं पूरी तरह से करूँगा!
ब्रायन पोस्टो

14
काउंटर-पॉइंट: पिछले एक-डेढ़ साल से मैंने इसके ठीक विपरीत नीति का पालन किया है: "यदि इसे किसी श्रेणी में लागू किया जा सकता है, तो ऐसा करें।" परिणामस्वरूप मेरा कोड बहुत अधिक संक्षिप्त, अधिक अभिव्यंजक है, और क्रिया नमूना कोड की तुलना में पढ़ने में आसान है जो Apple प्रदान करता है। मैंने एक नेमस्पेस संघर्ष के लिए लगभग 10 मिनट खो दिए हैं, और मैंने संभवतः अपने लिए बनाई गई दक्षता से मानव-महीने प्राप्त किए हैं। प्रत्येक अपने स्वयं के लिए, लेकिन मैंने जोखिमों को जानने के लिए इस नीति को अपनाया, और मुझे बहुत खुशी है कि मैंने किया।
cduhn

7
मैं सहमत नहीं हूँ। यदि यह एक फ़ंक्शन होने जा रहा है और यह एक फाउंडेशन ऑब्जेक्ट पर लागू होता है, और आप एक अच्छे नाम के बारे में सोच सकते हैं, तो इसे एक श्रेणी में चिपका सकते हैं। आपका कोड अधिक पठनीय होगा। मुझे लगता है कि वास्तव में यहाँ मुख्य बिंदु है: सब कुछ मॉडरेशन में करना।
mxcl

37

दुनिया को उपवर्ग का विरोध करना। कोको में बहुत कुछ प्रतिनिधिमंडल और अंतर्निहित रनटाइम के उपयोग के माध्यम से किया जाता है जो कि अन्य ढांचे में उपवर्ग के माध्यम से किया जाता है।

उदाहरण के लिए, जावा में आप अनाम *Listenerउपवर्गों के उदाहरणों का उपयोग करते हैं और .NET में आप अपने EventArgsउपवर्गों का बहुत अधिक उपयोग करते हैं । कोको में, आप या तो नहीं करते हैं - इसके बजाय लक्ष्य-क्रिया का उपयोग किया जाता है।


6
अन्यथा "विरासत पर रचना" के रूप में जाना जाता है।
एंड्रयू एबलिंग

37

उपयोगकर्ता जैसा चाहे स्ट्रिंग्स को सॉर्ट करें

जब आप उपयोगकर्ता को प्रस्तुत करने के लिए तार छाँटते हैं, तो आपको सरल compare:विधि का उपयोग नहीं करना चाहिए । इसके बजाय, आपको हमेशा स्थानीयकृत तुलना विधियों का उपयोग करना चाहिए जैसे कि localizedCompare:या localizedCaseInsensitiveCompare:

अधिक जानकारी के लिए, खोज, तुलना और छंटनी स्ट्रिंग्स देखें


31

घोषित किए गए गुण

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

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


26

नील मूल्यों के बारे में सोचो

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


मेरे पास यह है: #define SXRelease(o); o = nilऔर उसी के लिए CFReleaseऔर free। यह सब कुछ सरल करता है।

26

NSAssert और दोस्तों का उपयोग करें। मैं हर समय वैध वस्तु के रूप में nil का उपयोग करता हूं ... विशेष रूप से nil को संदेश भेजना Obj-C में पूरी तरह से मान्य है। हालांकि अगर मैं वास्तव में एक चर की स्थिति के बारे में सुनिश्चित करना चाहता हूं, तो मैं NSAssert और NSParameterAssert का उपयोग करता हूं, जो समस्याओं को आसानी से ट्रैक करने में मदद करता है।



23

सरल लेकिन अक्सर भूल जाने वाला। युक्ति के अनुसार:

सामान्य तौर पर, विभिन्न वर्गों में विधियाँ जिनका चयनकर्ता (समान नाम) होता है, को भी समान रिटर्न और तर्क प्रकार साझा करने होंगे। इस बाधा को गतिशील बाध्यकारी की अनुमति देने के लिए संकलक द्वारा लगाया जाता है।

जिस स्थिति में, सभी समान नाम वाले चयनकर्ता, भले ही विभिन्न वर्गों में हों , समान रिटर्न / तर्क प्रकार माना जाएगा। ये रहा एक सरल उदाहरण।

@interface FooInt:NSObject{}
-(int) print;
@end

@implementation FooInt
-(int) print{
    return 5;
}
@end

@interface FooFloat:NSObject{}
-(float) print;
@end

@implementation FooFloat
-(float) print{
    return 3.3;
}
@end

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
    id f1=[[FooFloat alloc]init];
    //prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
    NSLog(@"%f",[f1 print]);

    FooFloat* f2=[[FooFloat alloc]init];
    //prints 3.3 expectedly as the static type is FooFloat
    NSLog(@"%f",[f2 print]);

    [f1 release];
    [f2 release]
    [pool drain];

    return 0;
}   

भूलना आसान है। महत्वपूर्ण फिर भी
ब्रॉक वुल्फ

3
यह केवल एक चिंता है जब स्थैतिक टाइपिंग से बचना है। यदि संकलक को पता है, तो तर्क और वापसी के प्रकार समस्याओं के बिना भिन्न हो सकते हैं। निजी तौर पर, मुझे लगता है कि यह अक्सर एक समस्या नहीं है। Apple के पास बहुत सारे तरीके हैं जिनका एक ही नाम है लेकिन रिटर्न प्रकारों में भिन्नता है। अंत में, अस्पष्ट मामलों में आपको चेतावनी देने के लिए एक संकलक ध्वज है।
निकोलाई रुहे

अगर हम Apple के नामकरण कन्वेंशन गाइडलाइन का पालन करते हैं, तो यह स्थिति नहीं होगी :)
Eonil

22

यदि आप तेंदुए का उपयोग कर रहे हैं (Mac OS X 10.5) या बाद में, आप मेमोरी लीक को खोजने और ट्रैक करने के लिए इंस्ट्रूमेंट्स एप्लिकेशन का उपयोग कर सकते हैं। Xcode में अपना प्रोग्राम बनाने के बाद, रन> प्रदर्शन टूल से शुरू करें> लीक चुनें।

यहां तक ​​कि अगर आपका ऐप कोई लीक नहीं दिखाता है, तो आप वस्तुओं को बहुत लंबे समय तक रख सकते हैं। इंस्ट्रूमेंट्स में, आप इसके लिए ObjectAlloc इंस्ट्रूमेंट का उपयोग कर सकते हैं। अपने इंस्ट्रूमेंट्स डॉक्यूमेंट में ObjectAlloc इंस्ट्रूमेंट को चुनें, और व्यू> डिटेल को चुनकर इंस्ट्रूमेंट की डिटेल (अगर यह पहले से नहीं दिखा रहा है) लाएँ (इसके आगे एक चेक मार्क होना चाहिए)। ObjectAlloc विस्तार में "आवंटन जीवनकाल" के तहत, सुनिश्चित करें कि आप "निर्मित और फिर भी जीवित" के बगल में रेडियो बटन चुनते हैं।

अब जब भी आप अपने एप्लिकेशन को रिकॉर्ड करना बंद करते हैं, तो ObjectAlloc टूल का चयन आपको यह दिखाएगा कि "# नेट" कॉलम में आपके आवेदन में प्रत्येक अभी भी जीवित ऑब्जेक्ट के कितने संदर्भ हैं। सुनिश्चित करें कि आप न केवल अपनी कक्षाओं को देखते हैं, बल्कि आपके एनआईबी फाइलों के शीर्ष स्तर की वस्तुओं को भी देखते हैं। उदाहरण के लिए, यदि आपके पास स्क्रीन पर कोई विंडो नहीं है, और आप अभी भी रहने वाले NSWindow के संदर्भ देखते हैं, तो हो सकता है कि आपने इसे अपने कोड में जारी नहीं किया हो।


21

डीलॉक में सफाई करें।

यह सबसे आसान चीजों में से एक है - जासूसी। जब 150mph पर कोडिंग। डीललोक में हमेशा, हमेशा, हमेशा अपनी विशेषताओं / सदस्य चर को साफ करें।

- मैं ObjC 2 विशेषताओं का उपयोग करना चाहते के साथ नई डॉट नोटेशन - तो यह सफाई दर्द रहित बनाता है। अक्सर के रूप में सरल:

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

यह आपके लिए रिलीज़ की देखभाल करेगा और NULL को विशेषता सेट करेगा (जो मैं रक्षात्मक प्रोग्रामिंग पर विचार करता हूं - यदि किसी अन्य विधि में आगे प्रेषण में सदस्य चर को फिर से एक्सेस करता है - दुर्लभ लेकिन ऐसा हो सकता है)।

10.5 पर जीसी चालू होने के साथ, इसकी इतनी अधिक आवश्यकता नहीं है - लेकिन आपको अभी भी आपके द्वारा बनाए गए अन्य संसाधनों को साफ करने की आवश्यकता हो सकती है, आप इसे अंतिम विधि के बजाय कर सकते हैं।


12
सामान्य तौर पर आपको डीललॉक (या init) में एक्सेसर विधियों का उपयोग नहीं करना चाहिए ।
mmalc

1
प्रदर्शन कारणों के अलावा (एक्सेसर्स सीधे पहुंच की तुलना में थोड़ा धीमा हैं) मुझे डीललॉक या इनिट में एक्सेसर्स का उपयोग क्यों नहीं करना चाहिए?
schwa

1
(ए) प्रदर्शन कारण अपने आप में पूरी तरह से पर्याप्त कारण हैं (विशेषकर यदि आपके एक्सेसर्स परमाणु हैं)। (b) आपको किसी भी दुष्प्रभाव से बचना चाहिए जो एक्सेसर्स के पास हो सकता है। उत्तरार्द्ध विशेष रूप से एक मुद्दा है यदि आपकी कक्षा को उपवर्गित किया जा सकता है।
mmalc

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

1
मौसम या नहीं एक्सेसर विधियों का उपयोग करने पर एक और अधिक विस्तारित देखें / में गुण -initऔर -deallocतरीकों यहां पाया जा सकता है: mikeash.com/?page=pyblog/...
जोहान कूल

17

ये सभी टिप्पणियां बहुत अच्छी हैं, लेकिन मैं वास्तव में हैरान हूं कि किसी ने Google के उद्देश्य-सी स्टाइल गाइड का उल्लेख नहीं किया है जो कुछ समय पहले प्रकाशित हुआ था। मुझे लगता है कि उन्होंने बहुत गहन काम किया है।


7
हम्म, पहला उदाहरण पहले से ही बकवास से भरा है। भाषा के मुहावरों को कभी दस्तावेज न करें। अगर मुझे हेडर फ़ाइल में उन प्रकार की टिप्पणियाँ मिलती हैं, तो मैं पढ़ने में परेशान नहीं होता।
स्टेपहान एगरमोंट

5
ओह मेरी आँखें !!!!! मैं विश्वास नहीं कर सकता कि मैंने क्या देखा।
Eonil


13

यह मत भूलो कि NSWindowController और NSViewController NIB फ़ाइलों के शीर्ष-स्तरीय ऑब्जेक्ट को वे जारी करेंगे जो वे शासन करते हैं।

यदि आप मैन्युअल रूप से एक एनआईबी फ़ाइल लोड करते हैं, तो आप उस एनआईबी के शीर्ष-स्तरीय ऑब्जेक्ट को जारी करने के लिए जिम्मेदार हैं जब आप उनके साथ काम करते हैं।


12

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

Xcode वास्तव में उस अनुभाग के माध्यम से पार्स करेगा और इसे कोष्ठक, लूप, आदि के आधार पर इंडेंट करेगा। यह प्रत्येक और हर पंक्ति के लिए स्पेस बार या टैब कुंजी मारने की तुलना में बहुत अधिक कुशल है।


आप टैब को इंडेंट करने के लिए भी सेट कर सकते हैं और फिर सीएमडी-ए और टैब कर सकते हैं।
प्लूमनेटर

10

मुझे पता है कि जब मैंने पहली बार कोको प्रोग्रामिंग में देखा तो मैंने इसे अनदेखा कर दिया।

सुनिश्चित करें कि आप एनआईबी फाइलों के संबंध में स्मृति प्रबंधन जिम्मेदारियों को समझते हैं। आपके द्वारा लोड की गई किसी भी एनआईबी फ़ाइल में शीर्ष-स्तरीय ऑब्जेक्ट जारी करने के लिए आप जिम्मेदार हैं। विषय पर Apple का दस्तावेज़ीकरण पढ़ें ।


6
यह सच नहीं है। शीर्ष-स्तरीय ऑब्जेक्ट जारी करने के लिए आप जिम्मेदार हैं या नहीं, इस पर निर्भर करता है कि आप किस वर्ग से विरासत में प्राप्त कर रहे हैं और आप किस प्लेटफ़ॉर्म का उपयोग कर रहे हैं। अन्य लोगों के बीच डेवलपर देखें ।
mmalc

10

सभी जीसीसी चेतावनियों को चालू करें, फिर उन लोगों को बंद करें जो नियमित रूप से एप्पल के हेडर के कारण शोर को कम करते हैं।

क्लैंग स्टैटिक विश्लेषण भी अक्सर चलाएं; आप इसे "रन स्टेटिक एनालाइज़र" बिल्ड सेटिंग के माध्यम से सभी बिल्ड के लिए सक्षम कर सकते हैं।

इकाई परीक्षण लिखें और उन्हें प्रत्येक बिल्ड के साथ चलाएं।


और, यदि आप कर सकते हैं, तो "त्रुटियों के रूप में चेतावनी दें" चालू करें। बिना किसी चेतावनी के अस्तित्व में रहने दें।
पीटर होसे

2
अनुशंसित चेतावनी के साथ अपने प्रोजेक्ट को सेट करने के लिए एक आसान स्क्रिप्ट यहां उपलब्ध है: rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scpt
जोहान कूल

10

चर और गुण

1 / अपने हेडर को साफ रखना, कार्यान्वयन को छिपाना आपके हेडर
में उदाहरण चर शामिल नहीं है। निजी चर गुण के रूप में वर्ग निरंतरता में डालते हैं। सार्वजनिक चर आपके शीर्ष लेख में सार्वजनिक गुणों के रूप में घोषित होते हैं। यदि इसे केवल पढ़ा जाना चाहिए, तो इसे आसानी से घोषित करें और इसे कक्षा में निरंतरता के रूप में रीडराइट के रूप में अधिलेखित करें। मूल रूप से मैं चर का उपयोग नहीं कर रहा हूँ, केवल गुण।

2 / अपने गुणों को एक गैर-डिफ़ॉल्ट चर नाम दें, उदाहरण:


@synthesize property = property_;

कारण 1: आप "स्वयं" को भूलकर होने वाली त्रुटियों को पकड़ लेंगे। संपत्ति सौंपते समय। कारण 2: मेरे प्रयोगों से, लीक एनालाइज़र इन इंस्ट्रूमेंट्स में डिफ़ॉल्ट नाम के साथ लीक संपत्ति का पता लगाने में समस्याएं हैं।

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

दृश्य

1 / प्रत्येक दृश्य परिभाषा को एक जिब में डालें, यदि आप कर सकते हैं (अपवाद आमतौर पर गतिशील सामग्री और परत सेटिंग्स है)। यह समय बचाता है (कोड लिखना आसान है), इसे बदलना आसान है और यह आपके कोड को साफ रखता है।

2 / विचारों की संख्या कम करके विचारों को अनुकूलित करने का प्रयास न करें। केवल Xib के बजाय अपने कोड में UIImageView न बनाएं क्योंकि आप इसमें सबव्यू जोड़ना चाहते हैं। इसके बजाय पृष्ठभूमि के रूप में UIImageView का उपयोग करें। व्यू फ्रेमवर्क समस्याओं के बिना सैकड़ों विचारों को संभाल सकता है।

3 / IBOutlets हमेशा बनाए रखने की जरूरत नहीं है (या मजबूत)। ध्यान दें कि आपके अधिकांश IBOutlets आपके दृश्य पदानुक्रम का हिस्सा हैं और इस प्रकार अंतर्निहित रूप से बनाए रखा गया है।

4 / देखें सभी IBOutlets को व्यूडाउन में लोड करें

5 / कॉल देखें अपने प्रोलोक विधि से देखें। इसे अंतर्निहित नहीं कहा जाता है।

याद

जब आप उन्हें बनाते हैं तो 1 / ऑटोरेलिज़ ऑब्जेक्ट। आपकी रिलीज़ कॉल को एक-और शाखा में या एक वापसी विवरण के बाद स्थानांतरित करने के कारण कई कीड़े होते हैं। ऑटोरेलिज़ के बजाय रिलीज़ को केवल असाधारण स्थितियों में उपयोग किया जाना चाहिए - जैसे जब आप एक रनलूप की प्रतीक्षा कर रहे हैं और आप नहीं चाहते कि आपकी वस्तु बहुत जल्दी ऑटोरेल्ड हो जाए।

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

टिप्पणियाँ

1 / अपने कोड को ऑटोडेक्नोलेटेड बनाएं। प्रत्येक चर नाम और विधि नाम को बताना चाहिए कि वह क्या कर रहा है। यदि कोड सही तरीके से लिखा गया है (आपको इसमें बहुत अभ्यास की आवश्यकता है), तो आपको किसी भी कोड टिप्पणी (प्रलेखन टिप्पणियों के समान नहीं) की आवश्यकता नहीं होगी। एल्गोरिदम जटिल हो सकता है लेकिन कोड हमेशा सरल होना चाहिए।

2 / कभी-कभी, आपको एक टिप्पणी की आवश्यकता होगी। आमतौर पर एक गैर स्पष्ट कोड व्यवहार या हैक का वर्णन करने के लिए। यदि आपको लगता है कि आपको कोई टिप्पणी लिखनी है, तो पहले कोड को सरल बनाने के लिए और टिप्पणियों की आवश्यकता के बिना उसे फिर से लिखने का प्रयास करें।

खरोज

1 / बहुत अधिक इंडेंटेशन न बढ़ाएं। आपके अधिकांश विधि कोड विधि स्तर पर इंडेंट होने चाहिए। नेस्टेड ब्लॉक (यदि, आदि के लिए) पठनीयता कम हो जाती है। यदि आपके पास तीन नेस्टेड ब्लॉक हैं, तो आपको आंतरिक ब्लॉकों को एक अलग विधि में डालने का प्रयास करना चाहिए। चार या अधिक नेस्टेड ब्लॉकों का उपयोग कभी नहीं किया जाना चाहिए। यदि आपका अधिकांश विधि कोड if के अंदर है, तो if दशा को नकारें, उदाहरण:


if (self) {
   //... long initialization code ...
}

return self;

if (!self) {
   return nil;
}

//... long initialization code ...

return self;

C कोड को समझना, मुख्य रूप से C संरचना

ध्यान दें कि ओब्ज-सी, सी भाषा पर केवल एक हल्की ओओपी परत है। आपको समझना चाहिए कि सी काम में बुनियादी कोड संरचनाएं (एनम, स्ट्रक्चर, एरे, पॉइंटर्स आदि) कैसे हैं। उदाहरण:


view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);

के समान है:


CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;

और बहुत सारे

अपने स्वयं के कोडिंग मानकों के दस्तावेज़ों को बनाए रखें और इसे अक्सर अपडेट करें। अपने कीड़े से सीखने की कोशिश करें। समझें कि एक बग क्यों बनाया गया था और कोडिंग मानकों का उपयोग करके इससे बचने की कोशिश करें।

हमारे कोडिंग मानकों में वर्तमान में लगभग 20 पृष्ठ हैं, जावा कोडिंग मानकों का मिश्रण है, Google Obj-C / C ++ मानक और हमारे स्वयं के जोड़ हैं। अपने कोड का दस्तावेज़, मानक मानक इंडेंटेशन, सफेद रिक्त स्थान और सही स्थानों पर रिक्त लाइनों आदि का उपयोग करें।


9

अधिक कार्यात्मक बनें ।

ऑब्जेक्टिव-सी ऑब्जेक्ट-ओरिएंटेड लैंग्वेज है, लेकिन कोको फ्रेमवर्क फंक्शनल-स्टाइल अवेयर है, और कई मामलों में फंक्शनल स्टाइल डिजाइन किया गया है।

  1. उत्परिवर्तन का पृथक्करण है। प्राथमिक के रूप में अपरिवर्तनीय कक्षाओं का उपयोग करें , और माध्यमिक के रूप में परिवर्तनशील वस्तु। उदाहरण के लिए, मुख्य रूप से NSArray का उपयोग करें, और जब आवश्यक हो तभी NSMutableArray का उपयोग करें।

  2. शुद्ध कार्य है। ऐसा नहीं है, खरीदें कई फ्रेमवर्क एपीआई को शुद्ध फ़ंक्शन की तरह डिज़ाइन किया गया है। जैसे कार्यों को देखो CGRectMake()या CGAffineTransformMake()। स्पष्ट रूप से सूचक रूप अधिक कुशल दिखता है। हालांकि संकेत के साथ अप्रत्यक्ष तर्क पक्ष-प्रभाव-मुक्त की पेशकश नहीं कर सकता। यथासंभव विशुद्ध रूप से डिजाइन संरचनाएं। राज्य वस्तुओं को भी अलग करें। किसी वस्तु को मान देने के -copyबजाय उपयोग करें -retain। क्योंकि साझा स्थिति म्यूटेशन को अन्य ऑब्जेक्ट में चुपचाप मूल्य के लिए प्रभावित कर सकती है। तो साइड-इफ़ेक्ट-फ़्री नहीं हो सकता। यदि आपके पास बाहरी वस्तु से मूल्य है, तो इसे कॉपी करें। तो यह भी संभव के रूप में कम से कम साझा राज्य डिजाइन महत्वपूर्ण है।

हालांकि अशुद्ध कार्यों का भी उपयोग करने से डरो मत।

  1. आलसी मूल्यांकन है। -[UIViewController view]संपत्ति जैसा कुछ देखें । जब ऑब्जेक्ट बनाया जाएगा तो दृश्य नहीं बनाया जाएगा। यह तब बनाया जाएगा जब कॉलर viewपहली बार संपत्ति पढ़ रहा हो । UIImageतब तक लोड नहीं किया जाएगा जब तक कि इसे वास्तव में खींचा न जाए। इस डिजाइन की तरह कई कार्यान्वयन हैं। संसाधन प्रबंधन के लिए इस तरह के डिजाइन बहुत सहायक होते हैं, लेकिन यदि आप आलसी मूल्यांकन की अवधारणा को नहीं जानते हैं, तो उनके व्यवहार को समझना आसान नहीं है।

  2. बंद है। जितना हो सके सी-ब्लॉक्स का इस्तेमाल करें। यह आपके जीवन को बहुत सरल करेगा। लेकिन उपयोग करने से पहले ब्लॉक-मेमोरी-मैनेजमेंट के बारे में एक बार और पढ़ें।

  3. सेमी-ऑटो जीसी है। NSAutoreleasePool। -autoreleaseप्राथमिक का उपयोग करें । -retain/-releaseजब आपको वास्तव में जरूरत हो, तो सेकेंडरी का उपयोग करें । (पूर्व: स्मृति अनुकूलन, स्पष्ट संसाधन विलोपन)


2
3 के रूप में) मैं विपरीत दृष्टिकोण का प्रस्ताव देता हूं: जहां भी संभव हो मैनुअल मैनुअल / रिलीज का उपयोग करें! कौन जानता है कि इस कोड का उपयोग कैसे किया जाएगा - और यदि इसका उपयोग एक तंग लूप में किया जाएगा तो यह आपके मेमोरी उपयोग को अनावश्यक रूप से उड़ा सकता है।
ईको

@ Eiko यह सिर्फ एक समयपूर्व अनुकूलन है , सामान्य मार्गदर्शन नहीं हो सकता।
इयोनिल

1
मुझे लगता है कि यह एक डिजाइन चीज है, खासकर जब मॉडल कक्षाओं पर काम करना। मैं बढ़ती हुई स्मृति को एक दुष्प्रभाव के रूप में मानता हूं, और यह वह नहीं है जो मैं अक्सर प्रकट करना चाहता हूं। इससे भी बदतर, एक और डेवलपर जो मेरे कोड का उपयोग करता है, उसके पास ऑटोरेलिज़ पूल (यदि संभव हो तो - मेरी वस्तुओं को कुछ अन्य लाइब्रेरी कोड में भेजा जा सकता है) में महंगी कॉल लपेटने के अलावा कोई मौका नहीं है। और उन समस्याओं का बाद में निदान करना मुश्किल है, लेकिन पहली जगह में बचने के लिए सस्ता है। यदि आप उन वस्तुओं / ऑटोरेलिज़ वस्तुओं की नकल करते हैं जो पास हो गईं, तो आप खो सकते हैं यदि वे आपकी अपेक्षा से बहुत अधिक हैं। मैं जीयूआई कोड के साथ अधिक आराम कर रहा हूं, हालांकि।
ईको

@ ईको मैं मानता हूं autoreleaseकि आम तौर पर मेमोरी लंबे समय तक चलेगी , और मैनुअल retain/releaseमामले में मेमोरी की खपत को कम कर सकता है। हालांकि यह विशेष केस ऑप्टिमाइज़ेशन के लिए मार्गदर्शन होना चाहिए (यहां तक ​​कि आप हमेशा महसूस कर रहे हैं!), अभ्यास के रूप में समय से पहले अनुकूलन को सामान्य करने का कारण नहीं हो सकता है । और वास्तव में, आपका सुझाव मुझसे विपरीत नहीं है। मैंने इसे वास्तव में जरूरत के मामले के रूप में उल्लेख किया :)
Eonil
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.