मुझे स्पष्ट रूप से @synthesize का उपयोग कब करना चाहिए?


81

जहां तक ​​मुझे पता है, XCode 4.4 के बाद @synthesizeसे संपत्ति एक्सेसर्स को ऑटो-जेनरेट करेगा। लेकिन अभी-अभी मैंने कोड का एक नमूना पढ़ा है NSUndoManager, और कोड में यह देखा है कि यह @synthesizeस्पष्ट रूप से जोड़ा गया है। पसंद:

@interface RootViewController  ()

@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSUndoManager *undoManager;

@end

@implementation RootViewController
//Must explicitly synthesize this
@synthesize undoManager;

मैं अब हैरान महसूस कर रहा हूं ... मुझे @synthesizeअपने कोड में स्पष्ट रूप से कब जोड़ना चाहिए ?


1
नमूना कोड पुराना हो सकता है। मूल रूप से, इसका उपयोग तब तक करें जब तक कि यह एक समस्या में न बदल जाए (उदाहरण के लिए, प्रतिनिधियों में गुण ऑटो-संश्लेषित नहीं होंगे)
ब्रेनड्रॉन 5'13

1
टिप्पणी करने का प्रयास करें @sythesize। यदि कोड अभी भी काम करता है, तो यह आवश्यक नहीं है।
थॉमसडब्ल्यू

जवाबों:


171

बहुत सारे उत्तर हैं, लेकिन एक बड़ा भ्रम भी है। मैं कुछ ऑर्डर डालने की कोशिश करूंगा (या गड़बड़ी बढ़ाऊंगा, हम देखेंगे ...)

  1. आइए Xcode के बारे में बात करना बंद करें। Xcode एक IDE है । क्लैंग एक कंपाइलर है । इस विशेषता के बारे में हम चर्चा कर रहे हैं, इसे गुणों का स्वत: संश्लेषण कहा जाता है और यह क्लैंग द्वारा समर्थित एक ऑब्जेक्टिव-सी भाषा एक्सटेंशन है , जो कि Xcode द्वारा उपयोग किया जाने वाला डिफ़ॉल्ट कंपाइलर है।
    बस इसे स्पष्ट करने के लिए, यदि आप Xcode में gcc पर जाते हैं, तो आपको इस सुविधा (Xcode संस्करण से भिन्न) से कोई लाभ नहीं होगा। उसी तरह यदि आप एक टेक्स्ट एडिटर का उपयोग करते हैं और कमांड लाइन से क्लैंग का उपयोग कर संकलन करते हैं, तो आप। मर्जी।

  2. ऑटोसिंथेसिस के लिए धन्यवाद आपको संपत्ति को स्पष्ट रूप से संश्लेषित करने की आवश्यकता नहीं है क्योंकि यह संकलक द्वारा स्वचालित रूप से संश्लेषित किया जाएगा।

    @synthesize propertyName = _propertyName
    

    हालाँकि, कुछ अपवाद मौजूद हैं:

    • कस्टम गेट्टर और सेटर के साथ संपत्ति को फिर से लिखना

      गेट्टर और सेटर कस्टम कार्यान्वयन दोनों प्रदान करते समय , संपत्ति स्वचालित रूप से संश्लेषित नहीं की जाएगी

    • कस्टम गेट्टर के साथ आसानी से संपत्ति

      जब किसी प्रॉपर्टी के लिए एक कस्टम गेट्टर कार्यान्वयन प्रदान किया जाता है, तो यह स्वचालित रूप से संश्लेषित नहीं किया जाएगा

    • @ डायनामिक

      उपयोग करते समय @dynamic propertyName, संपत्ति स्वचालित रूप से संश्लेषित नहीं की जाएगी (बहुत स्पष्ट, चूंकि @dynamicऔर @synthesizeपारस्परिक रूप से अनन्य हैं)

    • एक @protocol में घोषित गुण

      किसी प्रोटोकॉल के अनुरूप होने पर, प्रोटोकॉल को परिभाषित करने वाली कोई भी संपत्ति स्वचालित रूप से संश्लेषित नहीं की जाएगी

    • एक श्रेणी में घोषित गुण

      यह एक ऐसा मामला है जिसमें @synthesizeनिर्देश स्वचालित रूप से संकलक द्वारा सम्मिलित नहीं किया जाता है, लेकिन इस गुण को मैन्युअल रूप से संश्लेषित नहीं किया जा सकता है। जबकि श्रेणियां संपत्तियों की घोषणा कर सकती हैं, उन्हें बिल्कुल भी संश्लेषित नहीं किया जा सकता है, क्योंकि श्रेणियां ivars नहीं बना सकती हैं। पूर्णता की खातिर, मैं जोड़ूंगा कि अभी भी उद्देश्य-सी रनटाइम का उपयोग करके संपत्ति संश्लेषण को नकली करना संभव है

    • ओवरराइड प्रॉपर्टीज (क्लैंग -600.0.51 के बाद से नया, Xcode 6 के साथ शिपिंग, धन्यवाद मार्क श्लुपमैन)

      जब आप एक सुपरक्लास की संपत्ति को ओवरराइड करते हैं, तो आपको इसे स्पष्ट रूप से संश्लेषित करना होगा

यह ध्यान देने योग्य है कि किसी संपत्ति का संश्लेषण स्वचालित रूप से बैकिंग आइवर को संश्लेषित करता है, इसलिए यदि संपत्ति संश्लेषण गायब है, तो आइवर भी गायब हो जाएगा, जब तक कि स्पष्ट रूप से घोषित नहीं किया जाता है।

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

ऊपर सूचीबद्ध मामलों के अलावा, एक स्पष्ट का केवल अन्य उपयोग @synthesizeएक अलग आइवर नाम निर्दिष्ट करने के लिए होगा। हालाँकि, कन्वेंशन महत्वपूर्ण हैं, इसलिए मेरी सलाह है कि हमेशा डिफ़ॉल्ट नामकरण का उपयोग करें।


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

3
एक श्रेणी में निर्दिष्ट गुण भी स्वचालित रूप से संश्लेषित नहीं होते हैं, जहां तक ​​मुझे याद है। (अंतर्निहित कारण यह है कि आप किसी श्रेणी में एक उदाहरण चर नहीं जोड़ सकते हैं।)
मार्टिन आर

@MartinR, अच्छी बात है। वे स्वचालित रूप से संश्लेषित नहीं होते हैं, लेकिन उन्हें मैन्युअल रूप से संश्लेषित नहीं किया जा सकता है क्योंकि @synthesizeएक श्रेणी में निषिद्ध है (श्रेणियों में कोई ivar, जैसा कि आपने पहले ही नोट किया है)। मैं एक नोट जोड़ूंगा।
गैब्रिएल पेट्रोनेला 20

लेकिन यह उत्तर विशिष्ट प्रश्न को संबोधित नहीं करता है: जब @synthesize का उपयोग किया जाना चाहिए? हमेशा, कभी नहीं, केवल जब कुछ शर्तों को पूरा किया जाता है?
जेफ

21

यदि आप स्पष्ट रूप से उपयोग नहीं करते हैं @synthesizeतो कंपाइलर आपकी संपत्ति को उसी तरह समझेगा जैसे आपने लिखा था

@synthesize undoManager=_undoManager;

तब आप अपनी कोड चीजों में लिख पाएंगे:

[_undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

यह आम सम्मेलन है।

अगर तुम लिखो

@synthesize undoManager;

आपके पास होगा :

[undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

व्यक्तिगत रूप से मैं उपयोग करना बंद कर देता हूं @synthesize, क्योंकि यह किसी भी अधिक अनिवार्य नहीं है। मेरे लिए उपयोग करने का एकमात्र कारण ए @synthesizeको लिंक iVarकरना है @property। यदि आप इसके लिए विशिष्ट गेट्टर और सेटर उत्पन्न करना चाहते हैं। लेकिन दिए गए कोड के कोड में कोई भी नहीं है iVar, मुझे लगता है कि यह @synthesizeबेकार है। लेकिन अब मुझे लगता है कि नया सवाल "कब उपयोग करना है iVar?", और इस एक के लिए "कभी नहीं" के अलावा मेरी कोई अन्य प्रतिक्रिया नहीं है!


2
सहमत, मैंने इसका उपयोग करना बंद कर दिया @synthesizeक्योंकि ऐसा करने का कोई कारण नहीं है। इसके अलावा प्रमुख अंडरस्कोर आपको एक अच्छा दृश्य ध्वज के रूप में कार्य करता है जिससे आपको पता चल सके कि आप मेमोरी प्रबंधन के आसपास काम कर रहे हैं और सुरक्षा जाल फैला रहे हैं जो कि गुण प्रदान करते हैं (जो आपको initऔर deallocतरीकों में लंघन होना चाहिए )।
बर्गसेस्टर

1
सवाल यह था कि आपको संश्लेषित करने की आवश्यकता कब है। आपने इसका जवाब नहीं दिया है।
फोगमिस्टर

1
मुझे आज पता चला कि यह बिल्कुल सच नहीं है। @Synthesize के बिना, आप बैकिंग इंस्टेंस चर बनाने के लिए जिम्मेदार हैं। इसके साथ, कंपाइलर इसे आपके लिए करेगा।
स्टीवन फिशर

1
और मैंने इस खोज के लिए किसी को वोट नहीं दिया। :)
स्टीवन फिशर

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

14

मुझे @synthesizeअपने कोड में स्पष्ट रूप से कब जोड़ना चाहिए ?

आम तौर पर, यदि यह आवश्यक है: आप शायद उस मामले से कभी नहीं टकराएंगे जहां इसकी आवश्यकता है।

एक मामला है कि आप इसे उपयोगी पा सकते हैं, हालांकि।

कहते हैं कि आप एक कस्टम गेट्टर और सेटर दोनों लिख रहे हैं, लेकिन इसे वापस करने के लिए एक उदाहरण चर चाहते हैं। (एक परमाणु संपत्ति के लिए, यह एक कस्टम सेटर के रूप में सरल है: कंपाइलर एक गेटर लिखेगा यदि आप एक मोनोटोमिक संपत्ति के लिए एक सेटर निर्दिष्ट करते हैं, लेकिन एक परमाणु संपत्ति नहीं।)

इस पर विचार करो:

@interface MyObject:NSObject
@property (copy) NSString *title;
@end

@implementation MyObject

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

यह काम नहीं करेगा, क्योंकि _titleमौजूद नहीं है। आपने एक गेटर या सेटर दोनों को निर्दिष्ट किया है, इसलिए Xcode (सही ढंग से) इसके लिए बैकिंग इंस्टेंस वेरिएबल नहीं बनाता है।

यहाँ छवि विवरण दर्ज करें

आपके पास इसे बनाने के लिए दो विकल्प हैं। आप इसे या तो बदल सकते हैं @implementation:

@implementation MyObject {
    NSString *_title;
}

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

या इसे इसमें बदलें:

@implementation MyObject

@synthesize title = _title;

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

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

अतीत में, मैंने उदाहरण चर को निर्दिष्ट करने का पक्ष लिया है @implementation {}, लेकिन मुझे अब लगता है कि @synthesizeमार्ग एक बेहतर विकल्प है क्योंकि यह निरर्थक प्रकार को हटा देता है और स्पष्ट रूप से बैकिंग चर को संपत्ति से जोड़ता है:

  1. संपत्ति का प्रकार बदलें, और उदाहरण चर का प्रकार बदलता है।
  2. इसके स्टोरेज क्वालिफायर को बदलें (उदाहरण के लिए, इसे कमजोर की बजाय मजबूत या मजबूत बनाएं) और स्टोरेज क्वालिफायर बदल जाते हैं।
  3. संपत्ति निकालें या नाम बदलें, और @synthesizeएक संकलक त्रुटि उत्पन्न करेगा। आप आवारा उदाहरण चर के साथ समाप्त नहीं होंगे।

* -मैं एक मामला जानता हूं जहां यह आवश्यक था, कई फाइलों में श्रेणियों के बीच बंटवारे की कार्यक्षमता से संबंधित। और मुझे आश्चर्य नहीं होगा अगर Apple इसे ठीक करता है, या पहले से ही है।


क्या आपको यकीन है? क्या आपने भी कोशिश की? मैंने कई कस्टम सेटर और गेटर्स लिखे और कभी भी मेरे गुणों को संश्लेषित नहीं किया। (और मैंने आपका पहला उदाहरण इस्तेमाल किया, जो आपने कहा था कि काम नहीं करता है)
मार्क

हाँ मुझे यकीन है। कोड एक नए प्रोजेक्ट से कॉपी-पेस्ट किया गया था। जब तक आप संपत्ति पर गैर-परमाणु निर्दिष्ट नहीं करते तब तक यह Xcode के हाल के संस्करणों पर काम नहीं करेगा ।
स्टीवन फिशर

1
हाँ, यह सच है .. लेकिन 99% समय आपके गुणों के लिए गैर-परमाणु है। तो केवल इस मामले में कि आपकी संपत्ति परमाणु है और आप एक कस्टम गेट्टर / सेटर चाहते हैं जिसे आपको वास्तव में संश्लेषित करने की आवश्यकता है।
मार्क

यदि आप सेटर और गेट्टर दोनों के लिए एक कस्टम कार्यान्वयन प्रदान करते हैं , तो कंपाइलर मान लेगा कि आप संपत्ति का नियंत्रण ले रहे हैं और यह आपके लिए इसे संश्लेषित नहीं करेगा।
गेब्रियल पेट्रोनेला 19

2
मैं वहां आपके साथ सहमत हूं, हालांकि मैं समझ सकता हूं कि ऐप्पल ने शुरू में क्यों सोचा कि यह एक अच्छा विचार था। असली दर्द यह है कि atomicबाद में प्रॉपर्टी स्पेसियर के रूप में नहीं जोड़ा गया था। अब जब यह वहां है, तो आपको चेतावनी झंडा CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIESदिलचस्प लग सकता है।
स्टीवन फिशर

7

ठीक है, जब आप एक संपत्ति बनाते हैं ...

@property NSString *name;

Xcode ऑटो iVar को संश्लेषित करेगा जैसे कि आपने लिखा था ...

@synthesize name = _name;

इसका मतलब है कि आप इसके साथ संपत्ति तक पहुँच सकते हैं ...

self.name;
// or
_name;

या तो काम करेगा लेकिन केवल self.nameएक्सेसर तरीके का उपयोग करता है।

केवल एक ही समय है कि ऑटो सिंथेसिस काम नहीं करता है: यदि आप अधिलेखित करते हैं लेकिन सेटर और गेट्टर विधि तो आपको आईवीआर को संश्लेषित करने की आवश्यकता होगी।

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

यद्यपि अंगूठे का एक नियम है।

IVars मत बनाओ। बस संपत्ति का उपयोग करें। इसे संश्लेषित न करें।


1
ऐसे और भी मामले हैं जिनमें ऑटोसिंथेसिस नहीं किया जाएगा। मेरे उत्तर की जाँच करें।
गैब्रियल पेट्रोनेला

@ गैब्रिएलेप्रोटेनेला क्या आप उन मामलों को औसत पाठक के लिए पूरी तरह से सूचीबद्ध कर सकते हैं?
दान रोसेनस्टार्क

@DanRosenstark अब किसी भी प्रोग्रामिंग के लिए अप्रासंगिक है। आपको वास्तव में स्विफ्ट का उपयोग करना चाहिए। और मुझे लगता है कि पूरे संश्लेषण की बात अब ओब्जेक्ट में भी एक चीज नहीं है। जब तक आप एक कोड आधार पर काम नहीं कर रहे हैं जो 5+ साल पुराना है।
फोगमिस्टर

@Fogmeister हाँ, यह अभी भी एक मामला है जो आप अपने जवाब में उल्लेख करते हैं (जहां आप सेटर और गेट्टर दोनों को ओवरराइड करते हैं)। और ऑब्जेक्टिव-सी के रूप में "अब किसी को प्रोग्रामिंग करने के लिए प्रासंगिक नहीं है" कृपया मेरी दिन की नौकरी को कॉल करें और उन्हें बताएं। फ़ेसबुक, गूगल और ऐप्पल को भी बताएं, जो आंतरिक रूप से वस्तुनिष्ठ उपयोग कर रहे हैं।
दान रोसेनस्टार्क

मुझे यकीन है कि इस Quora के बिना सच है हूँ, लेकिन वैसे भी: quora.com/...
दान Rosenstark

1

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


सच है, लेकिन यह सिर्फ एक मामला है। आप और अधिक विस्तृत करना चाह सकते हैं।
गैब्रियल पेट्रोनेला

@GabrielePetronella यह केवल एक ही है जो मैं इस देर घंटे में सोच सकता हूं। =]
लियो नटन

0

यह स्पष्ट करने के लिए धन्यवाद। मुझे भी ऐसी ही समस्या का समाधान करना पड़ा था।

@synthesize firstAsset, secondAsset, audioAsset;
@synthesize activityView;

इसलिए अब, उन्हें टिप्पणी करते हुए, मैंने उदाहरण के लिए प्रत्येक घटना को देखा और प्रतिस्थापित किया

self.firstAsset ऐसा लगता है कि मैं भी FirstAset का उपयोग कर सकता हूं, लेकिन मुझे लगता है कि मैं अक्सर " " को देखकर चूक जाता हूं


-1

Xcode को स्पष्ट @synthesizeघोषणा की आवश्यकता नहीं है ।

यदि आप ऐसा करते हुए नहीं लिखते @synthesizeहैं:

@synthesize manager = _manager;

नमूना कोड पुराना हो सकता है। वे जल्द ही इसे अपडेट करेंगे।

आप अपने गुणों का उपयोग कर सकते हैं जैसे:

[self.manager function];

यह Apple का अनुशंसित सम्मेलन है। मैं इसका पालन करता हूं, और मेरी सलाह है कि आप भी करें!


2
स्टेटमेंट [_manager function]संपत्ति तक नहीं पहुंचेगा, इसके बजाय यह अंतर्निहित आइवर को सीधे एक्सेस करेगा ।
काउचडॉलर

@ काउचड्यूपर यदि आप नाइटपैकिंग कर रहे हैं, तो आपको सटीक होना चाहिए। संपत्ति में आइवर सहित कुछ चीजें शामिल हैं। इसलिए यह कहना बेहतर है कि संपत्ति के एक्सेसरों का उपयोग[_manager function] नहीं करता है ।
निकोलाई रुहे

@CouchDeveloper - इसके लिए धन्यवाद! ठीक कर दिया! :)
सैम फिशर

1
@NikolaiRuhe आप सही निकोलाई हैं, मुझे और सटीक होना चाहिए था। ;)
काउचडॉलर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.