मैं उद्देश्य-सी में वर्ग-स्तरीय गुणों की घोषणा कैसे करूं?


205

शायद यह स्पष्ट है, लेकिन मैं नहीं जानता कि कैसे उद्देश्य-सी में वर्ग गुणों की घोषणा की जाए।

मुझे प्रति-वर्ग एक शब्दकोष को कैश करने की आवश्यकता है और आश्चर्य है कि इसे कक्षा में कैसे रखा जाए।

जवाबों:


190

Objective-C में संपत्तियों का एक विशिष्ट अर्थ है, लेकिन मुझे लगता है कि आप कुछ का मतलब है जो एक स्थिर चर के बराबर है? सभी प्रकार के फू के लिए केवल एक उदाहरण है?

ऑब्जेक्टिव-सी में क्लास फ़ंक्शंस घोषित करने के लिए आप इसके बजाय + उपसर्ग का उपयोग करते हैं - इसलिए आपका कार्यान्वयन कुछ इस तरह दिखाई देगा:

// Foo.h
@interface Foo {
}

+ (NSDictionary *)dictionary;

// Foo.m
+ (NSDictionary *)dictionary {
  static NSDictionary *fooDict = nil;
  if (fooDict == nil) {
    // create dict
  }
  return fooDict;
}

23
क्या यह सही है? शब्दकोश विधि की पहली पंक्ति के रूप में शून्य करने के लिए fooDict की स्थापना नहीं होगी, जिसके परिणामस्वरूप शब्दकोष को हर बार फिर से बनाया जा सकता है?
पापिल्लोनुकु


59
लाइन स्टैटिक NS सहारे * fooDict = nil; केवल एक बार निष्पादित हो जाएगा! यहां तक ​​कि कई बार नामक विधि में, कीवर्ड स्टेटिक के साथ घोषणा (और इस उदाहरण में भी प्रारंभिक) को अनदेखा किया जाएगा यदि कोई स्थिर चर इस नाम के साथ मौजूद है।
बिनियन

3
@ BenC.R.Leggiero हां, बिल्कुल। .-Accessor वाक्य रचना ऑब्जेक्टिव-सी में गुण से बंधा नहीं है, यह बस एक संकलित-इन शॉर्टकट किसी भी विधि के लिए कि किसी भी आर्ग लेने के बिना रिटर्न कुछ। इस मामले में मैं इसे पसंद करूंगा- मैं व्यक्तिगत रूप से .किसी भी उपयोग के लिए वाक्यविन्यास पसंद करता हूं, जहां क्लाइंट कोड कुछ पाने का इरादा रखता है, एक कार्रवाई नहीं करता है (भले ही कार्यान्वयन कोड एक बार कुछ बना सकता है, या साइड-इफेक्ट कार्रवाई कर सकता है) । भारी उपयोग के .सिंटैक्स का परिणाम अधिक-पठनीय कोड में भी होता है: […]एस का मतलब कुछ महत्वपूर्ण होता है जब .इसके बजाय सिंटैक्स का उपयोग किया जाता है।
स्लिप डी। थॉम्पसन

4
एलेक्स नोल्स्को के उत्तर पर एक नज़र डालें, वर्ग गुण Xcode 8 रिलीज़ के बाद से उपलब्ध हैं: stackoverflow.com/a/37849467/6666611
n3wbie

112

मैं इस समाधान का उपयोग कर रहा हूं:

@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end

@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end

और मैंने इसे सिंगलटन पैटर्न के प्रतिस्थापन के रूप में बेहद उपयोगी पाया।

इसका उपयोग करने के लिए, बस अपने डेटा को डॉट नोटेशन के साथ एक्सेस करें:

Model.value = 1;
NSLog(@"%d = value", Model.value);

3
यह वास्तव में अच्छा है। लेकिन selfएक कक्षा पद्धति के अंदर पृथ्वी पर क्या मतलब है?
टॉड लेहमैन

8
@ToddLehman selfवह वस्तु है जिसे संदेश प्राप्त हुआ है । और चूंकि कक्षाएं भी ऑब्जेक्ट हैं , इस मामले में selfइसका मतलब हैModel
स्पूकी

6
पाने वाले की आवश्यकता क्यों होगी @synchronized?
मैट कांटोर

1
यह वास्तव में बहुत अच्छा है कि यह काम करता है। कि आप अपने स्वयं के वर्ग स्तर के गुणों को राइट कर सकते हैं जो वास्तविक चीज़ की तरह काम करते हैं। मुझे लगता है कि स्वयं को सिंक्रनाइज़ करना आपकी संपत्ति की घोषणा में 'परमाणु' का उपयोग करने के बराबर है और यदि आप 'गैर-परमाणु' संस्करण चाहते हैं तो इसे छोड़ा जा सकता है? इसके अलावा, मैं '_' के साथ बैकिंग वैरिएबल के नामकरण पर विचार करूंगा क्योंकि सेब डिफ़ॉल्ट है और वापस आने / सेट करने के बाद से पठनीयता में भी सुधार होता है। गेट्टर / सेटर से अनंत पुनरावृत्ति का कारण बनता है। मेरी राय में यह सही उत्तर है।
पीटर सेगरब्लोम

3
यह अच्छा है, लेकिन ... 1 स्थिर सदस्य बनाने के लिए कोड की 10 लाइनें? क्या हैक है। Apple को बस इसे एक फीचर बनाना चाहिए।
जॉन हेनकेल

92

जैसा कि WWDC 2016 / XCode 8 ( LLVM सत्र @ 5: 05 में नया क्या है ) में देखा गया है। वर्ग के गुणों को निम्नानुसार घोषित किया जा सकता है

@interface MyType : NSObject
@property (class) NSString *someString;
@end

NSLog(@"format string %@", MyType.someString);

ध्यान दें कि वर्ग गुण कभी भी संश्लेषित नहीं होते हैं

@implementation
static NSString * _someString;
+ (NSString *)someString { return _someString; }
+ (void)setSomeString:(NSString *)newString { _someString = newString; }
@end

8
यह शायद स्पष्ट किया जाना चाहिए कि यह केवल गौण घोषणाओं के लिए चीनी है। जैसा कि आपने उल्लेख किया है, संपत्ति को संश्लेषित नहीं किया गया है: (ए static) चर अभी भी घोषित किया जाना चाहिए और उपयोग किया जाना चाहिए, और विधियों को स्पष्ट रूप से लागू किया गया है, जैसा कि वे पहले थे। डॉट सिंटैक्स पहले से ही पहले से ही काम कर रहा है। सभी में, यह वास्तव में है की तुलना में एक बड़ा सौदा की तरह लगता है।
jscs

6
बड़ी बात यह है कि आप स्विफ्ट कोड का उपयोग किए बिना () से सिंगलेट्स तक पहुंच सकते हैं, और कन्वेंशन द्वारा टाइप प्रत्यय हटा दिया जाता है। XYZMyClass.saredMyClass () के बजाय Eg XYZMyClass.saring (स्विफ्ट 3)
रयान

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

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

1
कार्यान्वयन को थ्रेड-सुरक्षित "सिंगलटन" व्यवहार के लिए आसानी से बढ़ाया जा सकता है, जो
डिस्पैच_ऑनके

63

यदि आप कक्षा-स्तरीय समकक्ष के लिए देख रहे हैं @property, तो उत्तर है "ऐसी कोई बात नहीं है"। लेकिन याद रखें, @propertyसिंटैक्टिक शुगर है, वैसे भी; यह सिर्फ उचित रूप से नामित ऑब्जेक्ट तरीके बनाता है।

आप ऐसे क्लास मेथड बनाना चाहते हैं जो स्टैटिक वैरिएबल्स तक पहुँचते हैं, जैसा कि दूसरों ने कहा है, केवल थोड़ा अलग सिंटैक्स है।


यहां तक ​​कि विचार गुण भी वाक्य-रचना हैं। फिर भी यह अच्छा होगा कि [MyClass वर्ग] के बजाय MyClass.class जैसे सामान के लिए डॉट सिंटैक्स का उपयोग किया जा सके।
ज़की जर्मन

4
@Zaky Deutsch आप कर सकते हैं! UIDevice.currentDevice.identifierForVendorमेरे लिये कार्य करता है।
टीसी

1
@tc। धन्यवाद! अब चुपचाप भरना। किसी कारण के लिए, मुझे विश्वास था कि मैंने अतीत में कोशिश की थी लेकिन यह काम नहीं किया। क्या यह किसी भी संयोग से एक नई विशेषता है?
ज़ाकी जर्मन

1
@Zaky Gem यह कम से कम एक या दो साल तक क्लास के तरीकों के लिए काम करता है। मेरा मानना ​​है कि यह हमेशा उदाहरण के तरीकों के लिए काम करता है अगर गेट्टर / सेटर विधियों में अपेक्षित प्रकार होते हैं।
टीसी

21

यहाँ यह करने का एक सुरक्षित तरीका है:

// Foo.h
@interface Foo {
}

+(NSDictionary*) dictionary;

// Foo.m
+(NSDictionary*) dictionary
{
  static NSDictionary* fooDict = nil;

  static dispatch_once_t oncePredicate;

  dispatch_once(&oncePredicate, ^{
        // create dict
    });

  return fooDict;
}

ये संपादन सुनिश्चित करते हैं कि fooDict केवल एक बार बनाया गया है।

से एप्पल प्रलेखन : "dispatch_once - एक ब्लॉक वस्तु एक बार और केवल एक आवेदन के जीवन भर के लिए एक बार पर क्रियान्वित।"


3
क्या एक स्थिर एनएसबर्ड + (एनएसएडर *) शब्दकोश विधि की पहली पंक्ति पर आरंभीकृत होने के बाद से डिस्पैच_ऑनस कोड अप्रासंगिक नहीं है और चूंकि यह स्थैतिक है, इसलिए इसे केवल एक बार ही शुरू किया जाएगा?
jcpennypincher

@jcpennypincher एक ही पंक्ति पर शब्दकोश को आरंभ करने का प्रयास कर रहा है क्योंकि इसकी स्थैतिक घोषणा निम्नलिखित संकलक त्रुटि पैदा करती है Initializer element is not a compile-time constant:।
जॉर्ज डब्ल्यूएस

@GeorgeWS आप केवल उस त्रुटि को प्राप्त कर रहे हैं क्योंकि आप इसे किसी फ़ंक्शन के परिणाम के लिए प्रारंभ करने का प्रयास कर रहे हैं (आवंटित और init फ़ंक्शन हैं)। यदि आप इसे nil को इनिशियलाइज़ करते हैं, और फिर if (obj == nil) जोड़ते हैं और वहाँ इनिशियलाइज़ करते हैं, तो आप ठीक हो जाएंगे।
रोब

1
रोब, वह धागा सुरक्षित नहीं है। यहां प्रस्तुत कोड सबसे अच्छा है।
इयान ओलमैन

मुझे यह उत्तर सबसे अच्छा लगता है, क्योंकि यह पूर्ण और धागा सुरक्षित है - हालांकि, यह केवल कार्यान्वयन के साथ बेहतर व्यवहार करता है, जबकि ऑप का प्रश्न वर्ग गुणों की घोषणा के बारे में था - उनका कार्यान्वयन नहीं (जिसका कार्यान्वयन से कोई लेना-देना नहीं है)। फिर भी धन्यवाद।
मोतिन शनर

11

Xcode 8 Objective-C के रूप में अब वर्ग गुणों का समर्थन करता है:

@interface MyClass : NSObject
@property (class, nonatomic, assign, readonly) NSUUID* identifier;
@end

चूंकि वर्ग गुण कभी भी संश्लेषित नहीं होते हैं इसलिए आपको अपना कार्यान्वयन लिखने की आवश्यकता होती है।

@implementation MyClass
static NSUUID*_identifier = nil;

+ (NSUUID *)identifier {
  if (_identifier == nil) {
    _identifier = [[NSUUID alloc] init];
  }
  return _identifier;
}
@end

आप वर्ग के नाम पर सामान्य डॉट सिंटैक्स का उपयोग करके वर्ग गुणों का उपयोग करते हैं:

MyClass.identifier;

7

गुणों का मूल्य केवल वस्तुओं में होता है, कक्षाओं में नहीं।

यदि आपको किसी वर्ग की सभी वस्तुओं के लिए कुछ स्टोर करने की आवश्यकता है, तो आपको एक वैश्विक चर का उपयोग करना होगा। आप इसे staticकार्यान्वयन फ़ाइल में घोषित करके छिपा सकते हैं ।

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

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


7

Xcode 8 से शुरू होकर, आप बेरी द्वारा बताए गए वर्ग गुण विशेषता का उपयोग कर सकते हैं ।

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

Sample.h

@interface Sample: NSObject
@property (class, retain) Sample *sharedSample;
@end

Sample.m

@implementation Sample
static Sample *_sharedSample;
+ ( Sample *)sharedSample {
   if (_sharedSample==nil) {
      [Sample setSharedSample:_sharedSample];
   }
   return _sharedSample;
}

+ (void)setSharedSample:(Sample *)sample {
   _sharedSample = [[Sample alloc]init];
}
@end

2

यदि आपके पास कई स्तर के गुण हैं तो एक सिंगलटन पैटर्न क्रम में हो सकता है। कुछ इस तरह:

// Foo.h
@interface Foo

+ (Foo *)singleton;

@property 1 ...
@property 2 ...
@property 3 ...

@end

तथा

// Foo.m

#import "Foo.h"

@implementation Foo

static Foo *_singleton = nil;

+ (Foo *)singleton {
    if (_singleton == nil) _singleton = [[Foo alloc] init];

    return _singleton;
}

@synthesize property1;
@synthesize property2;
@synthesise property3;

@end

अब अपने वर्ग-स्तरीय गुणों को इस तरह एक्सेस करें:

[Foo singleton].property1 = value;
value = [Foo singleton].property2;

4
यह सिंगलटन कार्यान्वयन थ्रेड सुरक्षित नहीं है, इसका उपयोग न करें
klefevre

1
बेशक यह थ्रेड सेफ नहीं है, आप थ्रेड सेफ्टी का उल्लेख करने वाले पहले व्यक्ति हैं और डिफ़ॉल्ट रूप से नॉन थ्रेड सेफ कॉन्टेक्ट्स यानी सिंगल थ्रेड में थ्रेड सेफ्टी ओवरलोड का कोई मतलब नहीं है।
पेड्रो बोर्जेस

dispatch_onceयहां उपयोग करना बहुत आसान होगा ।
इयान मैकडोनाल्ड

पीओ, घोषणा पक्ष पर एक उत्तर चाहता था, कार्यान्वयन नहीं - और यहां तक ​​कि सुझाए गए कार्यान्वयन अपूर्ण है (थ्रेड-सुरक्षित नहीं)।
मोतिन शोर

-3

[इस समाधान को आज़माएं यह सरल है] आप एक स्विफ्ट वर्ग में एक स्थिर चर बना सकते हैं, फिर इसे किसी भी उद्देश्य-सी कक्षा से बुला सकते हैं।


1
ओपी ने यह नहीं पूछा कि स्विफ्ट में एक स्थिर संपत्ति कैसे बनाई जाए, इससे उसकी समस्या हल नहीं होती है।
नाथन एफ।

या बल्कि, इसने समस्या को हल कर दिया, लेकिन सवाल का जवाब नहीं दिया। यकीन नहीं होता है कि अगर वह योग्य है और नीचे वोट ...
अमिताभ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.