क्या उद्देश्य-सी में दृढ़ता से टाइप किए गए संग्रह हैं?


140

मैं मैक / iPhone प्रोग्रामिंग और ऑब्जेक्टिव-सी के लिए नया हूं। C # और Java में हमारे पास "जेनेरिक" हैं, संग्रह कक्षाएं जिनके सदस्य केवल घोषित प्रकार के हो सकते हैं। उदाहरण के लिए, C # में

Dictionary<int, MyCustomObject>

केवल कुंजियाँ हो सकती हैं जो पूर्णांक और मान हैं जो प्रकार MyCustomObject के हैं। क्या ऑब्जेक्टिव-सी में एक समान तंत्र मौजूद है?


बस खुद ओब्जेसी के बारे में सीखना शुरू कर दिया। शायद आप भारी उठाने के लिए ObjC ++ का उपयोग कर सकते हैं?
टॉयबिल्डर

इस प्रश्न के उत्तर में आपकी रुचि हो सकती है: क्या NSArray, NSMutableArray, आदि पर टाइपिंग को लागू करने का कोई तरीका है? । तर्क दिए गए हैं कि यह उद्देश्य-सी / कोको में सामान्य अभ्यास क्यों नहीं है।
मौविसील

2
ObjC ++ वास्तव में एक भाषा नहीं है ... बस C ++ इनलाइन को संभालने के लिए ओबजैक की क्षमता को संदर्भित करने का एक तरीका अधिक है जैसे ही यह सी को हैंडल करेगा। आपको ऐसा तब तक नहीं करना चाहिए जब तक कि आपको ज़रूरत न हो, (जैसे कि यदि आपको ज़रूरत है तृतीय-पक्ष लाइब्रेरी का उपयोग करने के लिए जिसे C ++ में लिखा गया था)।
मार्क डब्ल्यू


@ मार्क डब्ल्यू - "ऐसा नहीं करना चाहिए" क्यों नहीं? मैंने ObjC ++ का उपयोग किया है और यह बहुत अच्छा काम करता है। मैं #import <map> और @property std :: map <int, NSString *> myDict; मैं पूर्ण कोको एपीआई का उपयोग कर सकता हूं और दृढ़ता से टाइप किए गए संग्रह कर सकता हूं। मुझे कोई डाउन-साइड नहीं दिख रहा है।
जॉन हेनकेल

जवाबों:


211

Xcode 7 में, Apple ने ऑब्जेक्टिव-सी के लिए 'लाइटवेट जेनरिक' पेश किया है। ऑब्जेक्टिव-सी में, वे एक प्रकार का बेमेल होने पर कंपाइलर चेतावनी उत्पन्न करेंगे।

NSArray<NSString*>* arr = @[@"str"];

NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'

और स्विफ्ट कोड में, वे एक संकलक त्रुटि उत्पन्न करेंगे:

var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'

लाइटवेट जेनेरिक का उपयोग NSArray, NSDictionary और NSSet के साथ किया जाता है, लेकिन आप इन्हें अपनी कक्षाओं में भी जोड़ सकते हैं:

@interface GenericsTest<__covariant T> : NSObject

-(void)genericMethod:(T)object;

@end

@implementation GenericsTest

-(void)genericMethod:(id)object {}

@end

ऑब्जेक्टिव-सी का व्यवहार वैसा ही होगा जैसा उसने पहले कंपाइलर चेतावनियों के साथ किया था।

GenericsTest<NSString*>* test = [GenericsTest new];

[test genericMethod:@"string"];
[test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'

लेकिन स्विफ्ट जेनरिक जानकारी को पूरी तरह से नजरअंदाज कर देगा। (स्विफ्ट 3+ में अब सच नहीं है।)

var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'

इन फाउंडेशन कलेक्शन क्लासेस के अलावा, ऑब्जेक्टिव-सी लाइटवेट जेनेरिक को स्विफ्ट ने नजरअंदाज कर दिया है। हल्के जेनेरिक का उपयोग करने वाले किसी भी अन्य प्रकार को स्विफ्ट में आयात किया जाता है जैसे कि वे अपरिवर्तित थे।

उद्देश्य-सी एपीआई के साथ बातचीत


चूँकि मेरे पास जेनेरिक और प्रकारों के बारे में प्रश्न हैं, इसलिए मैंने अपना प्रश्न अलग-अलग सूत्र में पूछा, सब कुछ स्पष्ट रखने के लिए: stackoverflow.com/questions/30828076/…
lvp

2
@rizzes। हां, यह सिर्फ पेश किया गया था।
कॉनर

यहाँ एक चेतावनी यह है कि स्विफ्ट आपके जेनेरिक ओब्जेक्ट वर्ग में प्रकार एनोटेशन को पूरी तरह से अनदेखा नहीं करता है । यदि आप बाधाओं को निर्दिष्ट करते हैं, उदाहरण के लिए MyClass <Foo: id<Bar>>, आपका स्विफ्ट कोड मान लेगा कि आपके अवरोध का प्रकार है, जो आपको कुछ काम करने के लिए देता है । हालांकि, विशेष उपवर्गों में MyClassउनके विशेष प्रकारों को अनदेखा किया जाएगा (प्रभावी रूप से एक जेनेरिक के समान ही देखा जाएगा MyClass)। देखें github.com/bgerstle/LightweightGenericsExample
ब्रायन गेर्स्टल

तो क्या यह 10.10, 10.9 और पहले के ऑपरेटिंग सिस्टम के लिए संकलित है?
p0lAris

जब तक आप उन्हें समर्थन देने के लिए अपना परिनियोजन लक्ष्य निर्धारित करते हैं, तब तक
कॉनर

91

यह उत्तर पुराना है लेकिन ऐतिहासिक मूल्य के लिए बना हुआ है। Xcode 7 के रूप में, जून 8 '15 से कॉनर का उत्तर अधिक सटीक है।


नहीं, जब तक आप अपने स्वयं के कस्टम संग्रह वर्गों (जो मैं दृढ़ता से हतोत्साहित करता हूं) में C ++ टेम्पलेट का उपयोग नहीं करना चाहते हैं, तो Objective-C में कोई भी जेनरिक नहीं हैं।

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

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


88
मैं "चिंता न करें, बस उन वस्तुओं को संदेश भेजें"। यदि आप संग्रह में गलत प्रकार की वस्तुओं को डालते हैं, जो इन संदेशों का जवाब नहीं देते हैं, तो यह रनटाइम त्रुटियों को उत्पन्न करेगा। अन्य भाषाओं में जेनेरिक का उपयोग करना संकलन समय की जाँच के साथ इस समस्या से बचा जाता है।
हेनिंग77

8
@ henning77 हाँ, लेकिन उद्देश्य-सी इन भाषाओं की तुलना में अधिक गतिशील भाषा है। यदि आप मजबूत प्रकार-सुरक्षा चाहते हैं, तो उन भाषाओं का उपयोग करें।
रफ़ी खाचदौरीयन १६'१२ को

36
मैं दर्शन की चिंता न करने से भी असहमत हूं - उदाहरण के लिए यदि आप एक NSArray से पहली वस्तु को निकालते हैं और उसे एक NSNumber पर
डालते

13
@RaffiKhatchadourian - अगर आप iOS ऐप लिख रहे हैं तो ज्यादा विकल्प नहीं हैं। यदि जावा के साथ एक लिखना सरल था, और एक मूल एप्लिकेशन लिखने के सभी लाभ मिलते हैं, तो मेरा विश्वास करें: मैं करूंगा।
एरिकोस्को

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

11

नहीं, लेकिन इसे स्पष्ट करने के लिए आप इसे उस प्रकार के ऑब्जेक्ट के साथ टिप्पणी कर सकते हैं जिसे आप स्टोर करना चाहते हैं, मैंने इसे कई बार देखा है जब आपको जावा 1.4 में आजकल कुछ लिखने की आवश्यकता होती है) जैसे:

NSMutableArray* /*<TypeA>*/ arrayName = ....

या

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...

मुझे लगता है कि यह एक अच्छा तरीका है कि इसे प्रलेखित किया जाए, यदि कोई व्यक्ति आपके कोड को पढ़ता है। वैसे भी चर का नाम जितना संभव हो उतना स्पष्ट होना चाहिए ताकि यह पता चल सके कि इसमें क्या वस्तुएं हैं।
htafoya

6

Objective-C में कोई Generics नहीं हैं।

डॉक्स से

एरे को वस्तुओं के संग्रह का आदेश दिया जाता है। कोको कई सरणी कक्षाएं, NSArray, NSMutableArray (NSArray का एक उपवर्ग) और NSPointerArray प्रदान करता है।


उत्तर में डॉक का लिंक मृत है - "क्षमा करें, वह पृष्ठ नहीं मिल सकता है"
पैंग

6

Apple ने XCode 7 में ObjC में जेनरिक जोड़ दिया है:

@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

यहां देखें: https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTataTes.html#//apple_ref/doc/uid/TP40014216-CH6-ID6-ID61


5

यह Xcode 7 (अंत में जारी किया गया था !)

ध्यान दें कि ऑब्जेक्टिव सी कोड में, यह केवल एक संकलन-समय की जांच है; केवल गलत प्रकार को संग्रह में रखने या टाइप की गई संपत्ति को असाइन करने के लिए कोई रन-टाइम त्रुटि नहीं होगी।

घोषित:

@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end

उपयोग:

FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];

उन *एस के बारे में सावधान रहें ।


4

सामान्य NSArrays को उपवर्ग द्वारा महसूस किया जा सकता है NSArray, और अधिक प्रतिबंधक वाले सभी प्रदान किए गए तरीकों को फिर से परिभाषित किया जा सकता है। उदाहरण के लिए,

- (id)objectAtIndex:(NSUInteger)index

में पुनर्परिभाषित करना होगा

@interface NSStringArray : NSArray

जैसा

- (NSString *)objectAtIndex:(NSUInteger)index

एक NSArray के लिए केवल NSStrings शामिल करने के लिए।

निर्मित उपवर्ग का उपयोग ड्रॉप-इन प्रतिस्थापन के रूप में किया जा सकता है और कई उपयोगी विशेषताएं ला सकता है: कंपाइलर चेतावनी, संपत्ति का उपयोग, बेहतर कोड निर्माण और Xcode में -प्राप्ति। ये सभी संकलन-समय की विशेषताएं हैं, वास्तविक कार्यान्वयन को फिर से परिभाषित करने की आवश्यकता नहीं है - NSArray के तरीकों का अभी भी उपयोग किया जा सकता है।

इसे स्वचालित करना और इसे केवल दो बयानों तक उबालना संभव है, जो इसे उन भाषाओं के करीब लाता है जो जेनरिक का समर्थन करते हैं। मैंने WMGenericCollection के साथ एक ऑटोमेशन बनाया है , जहां टेम्प्लेट C प्रीप्रोसेसर मैक्रोज़ के रूप में दिए गए हैं।

मैक्रो युक्त हेडर फ़ाइल आयात करने के बाद, आप दो विवरणों के साथ एक सामान्य NSArray बना सकते हैं: एक इंटरफ़ेस के लिए और एक कार्यान्वयन के लिए। आपको केवल वह डेटा प्रकार प्रदान करना होगा जिसे आप अपने उपवर्गों के लिए संग्रहीत और नाम देना चाहते हैं। WMGenericCollection ऐसे टेम्प्लेट प्रदान करता है NSArray, NSDictionaryऔर NSSet, साथ ही उनके परस्पर समकक्ष भी।

एक उदाहरण: List<int>एक कस्टम वर्ग द्वारा महसूस किया जा सकता है NumberArray, जिसे निम्नलिखित कथन के साथ बनाया गया है:

WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
                         // generated class names
                         NumberArray, MutableNumberArray)

एक बार बना लेने के बाद NumberArray, आप इसे अपने प्रोजेक्ट में हर जगह उपयोग कर सकते हैं। इसमें सिंटैक्स की कमी है <int>, लेकिन आप इन्हें टेम्प्लेट के रूप में कक्षाओं के रूप में लेबल करने के लिए अपनी स्वयं की नामकरण योजना चुन सकते हैं।


ध्यान दें कि वही CoreLib में मौजूद है: github.com/core-code/CoreLib/blob/master/CoreLib/CoreLib.h#L105
user1259710


2

अब सपने सच होते हैं - आज से ऑब्जेक्टिव-सी में जेनरिक हैं (धन्यवाद, डब्ल्यूडब्ल्यूडीसी)। यह कोई मजाक नहीं है - स्विफ्ट के आधिकारिक पेज पर :

नई वाक्य रचना विशेषताएँ आपको भाषा में निरंतरता में सुधार करते हुए अधिक अभिव्यंजक कोड लिखने देती हैं। एसडीके ने स्विफ्ट कोड को क्लीनर और सुरक्षित बनाने के लिए जेनेरिक और अशक्तता एनोटेशन जैसी नई उद्देश्य-सी विशेषताओं को नियोजित किया है। यहाँ केवल स्विफ्ट 2.0 एन्हांसमेंट का एक नमूना है।

और छवि जो इस बात का प्रमाण देती है:उद्देश्य-सी जेनरिक


2

बस यहां कूदना चाहते हैं। मैंने यहाँ पर Generics के बारे में एक ब्लॉग पोस्ट लिखा है ।

मैं जो योगदान देना चाहता हूं वह यह है कि जेनरिक को किसी भी वर्ग में जोड़ा जा सकता है , न कि केवल संग्रह कक्षाओं के रूप में, जैसा कि ऐप्पल इंगित करता है।

मैंने सफलतापूर्वक कई प्रकार की कक्षाओं में जोड़ा है क्योंकि वे Apple के संग्रह के समान ही काम करते हैं। अर्थात। संकलित समय जाँच, कोड पूरा होने, जातियों को हटाने में सक्षम, आदि।

का आनंद लें।


-2

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

Example:
    -(id) sort (id) obj;  // too generic. catches all.
     // better
    -(id) sort: (EasilySortableCollection*) esc;
    -(id) sort: (HardToSortCollection*) hsc; 
    ...
    [Sorter  sort: MyEasyColl];
    [Sorter  sort: MyHardColl];
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.