2010-10-05 23 views
18

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

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

उत्तर

32

NSMutableArray एक ठोस वर्ग नहीं है, यह केवल वर्ग क्लस्टर का सार सुपरक्लास है। NSMutableArray के लिए प्रलेखन में subclass के बारे में जानकारी है, लेकिन दृढ़ता से आपको सलाह नहीं देता है! यदि आपके पास वास्तविक संग्रहण की विशेष आवश्यकता है तो केवल उप-वर्ग।

कक्षा क्लस्टर का अर्थ है कि वास्तविक कक्षा रन-टाइम पर चुनी जाएगी। एक सरणी खाली बनाई गई है, जो 1000 वस्तुओं के साथ बनाई गई सरणी के समान कक्षा का उपयोग नहीं कर सकती है। रन-टाइम आपके लिए उपयोग किए जाने वाले कार्यान्वयन के स्मार्ट विकल्प कर सकता है। अभ्यास में NSMutableArray एक ब्रिज CFArray होगा। आपको चिंता करने की ज़रूरत नहीं है, लेकिन अगर आप डीबगर में अपने सरणी के प्रकार का निरीक्षण करते हैं, तो आप इसे देख सकते हैं, आप कभी भी NSArray नहीं देखेंगे, लेकिन अक्सर NSCFArray देखेंगे।

जैसा कि पहले उल्लेख किया गया है, सबक्लासिंग कक्षा को विस्तारित करने जैसा नहीं है। उद्देश्य-सी में श्रेणियों की अवधारणा है। एक श्रेणी अन्य प्रोग्रामिंग भाषाओं के समान है जो मिश्रण-इन्स को कॉल करती है।

आप उदाहरण के लिए एक संपत्ति पर सभी सदस्यों को सॉर्ट करने NSMutableArray पर एक सुविधा की विधि चाहते हैं, तो श्रेणी इंटरफ़ेस एक ज फ़ाइल में इस तरह के रूप में परिभाषित:

@interface NSMutableArray (CWFirstnameSort) 
-(void)sortObjectsByProperty:(NSString*)propertyName; 
@end 

और कार्यान्वयन होगा:

@implementation NSMutableArray (CWFirstnameSort) 
-(void)sortObjectsByProperty:(NSString*)propertyName; 
{ 
    NSSortDescriptor* sortDesc = [NSSortDescriptor sortDescriptorWithKey:propertName ascending:YES]; 
    [self sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]]; 
} 
@end 

तो बस के रूप में उपयोग:

[people sortObjectsByProperty:@"firstName"]; 
5

यदि आप केवल एक कस्टम विधि जोड़ रहे हैं, तो NSMutableArray पर एक श्रेणी का उपयोग करें। यह एक वर्ग क्लस्टर है, इसलिए कार्यान्वयन अनियंत्रित उप-वर्गों द्वारा प्रदान किया जाता है। आपको अपना स्वयं का उप-वर्ग उत्पन्न करने के लिए कुछ विधियां प्रदान करने की आवश्यकता है। हालांकि, अगर आप केवल एक श्रेणी जोड़ते हैं तो आपकी कस्टम विधि आपके ऐप में सभीNSMutableArrays पर काम करेगी।

तुलना के लिए, यहां एक उदाहरण है जिसे मैंने implementing a custom NSMutableArray subclass के कुछ समय पहले लिखा था।

+1

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

+1

@PeyloW: एक अच्छी सैद्धांतिक स्थिति लेने के लिए, लेकिन आखिरकार असली दुनिया कोड है जहां टाइप सुरक्षा उपयोगी हो सकती है। जैसा कि मैंने लिखा पोस्ट में वर्णित है, आप उस बिंदु पर आगे की विफलता लाते हैं जहां इसे इंजेक्शन दिया गया है, कुछ मनमाने ढंग से बाद में नहीं। इससे दुर्भावनापूर्ण ऑब्जेक्ट प्रतिस्थापन की संभावना को हटाकर हमले की सतह कम हो गई। –

+1

@PeyloW: असली दुनिया कोड भी है जिसे CoreFoundation में इंटरफ़ेस करने की आवश्यकता है। यह इस बात पर परवाह करता है कि आपका म्यूटेबल सरणी कार्यान्वयन वास्तव में एक एनएसएमयूटेबलएरे सबक्लास या कुछ और है; जिस बिंदु पर आपके कार्यान्वयन में बेहतर सबक्लास एनएसएमयूटेबलएरे था। –

4

उद्देश्य-सी में Categories नामक मौजूदा कक्षाओं के तरीकों को जोड़ने के लिए एक तंत्र है। इस तरह आपको अपना खुद का उप-वर्ग बनाना नहीं है।

+0

लिंक अब खराब है। क्या कोई नया काम करता है? – JohnK

+0

मैंने लिंक अपडेट किया। –

2

मैं टी है o नोड निंजा और पेलोव दोनों के साथ सहमत हैं क्योंकि तकनीकी रूप से उनके पास दोनों अधिकार हैं। असल में, यह मुझे बहुत मदद नहीं करता है।

प्रस्तावना: कोड में कई सरणी हैं जिनमें से सभी में केवल एक ही है लेकिन विभिन्न प्रकार के डेटा उदा। कक्षा ए, कक्षाबी, कक्षा सी।

समस्या: मैं आसानी से गलत से गुज़रने के द्वारा सरणी मिश्रण कर सकता हूं उदा। कुछ चयनकर्ता क्योंकि वे सभी एनएसएमयूटेबलएरे हैं। कोई स्थैतिक जांच नहीं है, केवल रनटाइम एक है।

समाधान - 1 कोशिश: NSMutableArray की मेक उपवर्ग तो संकलक स्थिर जांच करता है और के बारे में गलत डेटा प्रकार चेतावनी देते हैं।

यह अच्छा है क्योंकि संकलक आपको तब भी चेतावनी देता है जब आप गलत टाइप करते हैं -addObject या -objectAtIndex जब आप उनको ओवरलोड करते हैं। यह बुरा है क्योंकि आप इस तरह से NSMutableArray superclass को तुरंत चालू नहीं कर सकते हैं।

समाधान - दूसरा प्रयास: कुछ प्रकार की नई (प्रॉक्सी) कक्षा बनाएं उदा। एनएसओब्जेक्ट एनएसएमयूटेबलएरे के लिए और एनएसएमयूटेबलएरे के प्रकार के वर्ग सदस्य जोड़ें।

यह अच्छा है क्योंकि जब आप गलत टाइप करते हैं तो आप NSMutableClass और कंपाइलर चेक को तत्काल कर सकते हैं -addObject या -objectAtIndex जब आप इसे अधिभारित करते हैं।

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

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

-1

NSArray के लिए एप्पल संदर्भ से, तरीके में खंड ओवरराइड:

NSArray का कोई भी उपवर्ग ओवरराइड चाहिए आदिम उदाहरण तरीकों गिनती और objectAtIndex :. इन तरीकों को बैकिंग स्टोर पर काम करना चाहिए जो आप संग्रह के तत्वों के लिए प्रदान करते हैं। इस बैकिंग स्टोर के लिए आप एक स्थिर सरणी, मानक एनएसएआरएआरई ऑब्जेक्ट, या कुछ अन्य डेटा प्रकार या तंत्र का उपयोग कर सकते हैं। आप किसी भी अन्य एनएसएआरएआर विधि के लिए आंशिक रूप से या पूरी तरह से ओवरराइड करना चुन सकते हैं जिसके लिए आप वैकल्पिक कार्यान्वयन प्रदान करना चाहते हैं।

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

एक सार विधि, निम्न उत्पादन के साथ करता है, तो ओवरराइड नहीं जो एक अपवाद को जन्म देती है, के रूप में

इस विधि परिभाषा में कार्य करता है:

-someAbstractFooMethod केवल अमूर्त वर्ग के लिए परिभाषित किया। परिभाषित करें - [YourClassName someAbstractFooMethod]!

- (void) someAbstractFooMethod 
{ 
    //Force subclassers to override this method 
    NSString *methodName = NSStringFromSelector(_cmd); 
    NSString *className = [self className]; 
    [NSException raise:NSInvalidArgumentException 
       format:@"-%@ only defined for abstract class. Define -[%@ %@]!", methodName, className, methodName]; 
} 
1

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

क्या आप एनएसएमयूटेबलएरे (या एनएसएआरएआरई) को उपclass करना चाहिए? आप जो हासिल करना चाहते हैं उस पर निर्भर करता है। यदि आप सरणी की तरह किसी सरणी की मूलभूत कार्यक्षमता को बढ़ाने के लिए केवल एक विधि जोड़ना चाहते हैं, तो @PayloW का उत्तर Categories तरीका है। हालांकि, अगर आप एक कस्टम क्लास बनाना चाहते हैं जो किसी सरणी की तरह व्यवहार करता है तो हाँ, NSMutableArray उपclassing काफी आसान है। लेकिन क्योंकि यह क्लास क्लस्टर है क्योंकि यह अपेक्षा करता है कि आप वास्तव में उपclass नहीं करते हैं। आम तौर पर सुपर क्लास में उपलब्ध विधियों को उप-वर्गीकरण में आपके उप-वर्ग में उपलब्ध हैं या आप उन्हें ओवरराइड कर सकते हैं। कक्षा क्लस्टर के साथ आपको इसके बजाय सुपर विधियों को शामिल करना होगा जिन्हें आप उपयोग करने जा रहे हैं और उन विधियों को लपेटने के लिए सुपर क्लास के _backend इंस्टेंस प्रदान करते हैं।

इंटरफ़ेस::

@interface MyCustomArrayClass : NSMutableArray { 

    // Backend instance your class will be using 
    NSMutableArray *_backendArray; 
} 

// *** YOUR CUSTOM METHODS HERE (no need to put the Super's methods here) *** 

-(bool)isEmpty; 
-(id)nameAtIndex:(int)index; 
-(int)rowAtIndex:(int)index; 
-(int)columnAtIndex:(int)index; 

@end 

कार्यान्वयन:

@implementation MyCustomArrayClass 

-(instancetype)init { 

    if (self = [super init]) {    
     _backendArray = [@[] mutableCopy]; 
    } 

    return self; 
} 

// *** Super's Required Methods (because you're going to use them) *** 

-(void)addObject:(id)anObject { 
    [_backendArray addObject:anObject]; 
} 

-(void)insertObject:(id)anObject atIndex:(NSUInteger)index { 
    [_backendArray insertObject:anObject atIndex:index]; 
} 

-(void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { 
    [_backendArray replaceObjectAtIndex:index withObject:anObject]; 
} 

-(id)objectAtIndex:(NSUInteger)index { 
    return [_backendArray objectAtIndex:index]; 
} 

-(NSUInteger)count { 
    return _backendArray.count; 
} 

-(void)removeObject:(id)anObject { 
    [_backendArray removeObject:anObject]; 
} 

-(void)removeLastObject { 
    [_backendArray removeLastObject]; 
} 

-(void)removeAllObjects { 
    [_backendArray removeAllObjects]; 
} 

-(void)removeObjectAtIndex:(NSUInteger)index { 
    [_backendArray removeObjectAtIndex:index]; 
} 

// *** YOUR CUSTOM METHODS *** 

-(bool)isEmpty { 
    return _backendArray.count == 0; 
} 

-(id)nameAtIndex:(int)index { 
    return ((MyObject *)_backendArray[index]).name; 
} 

-(int)rowAtIndex:(int)index { 
    return ((MyObject *)_backendArray[index]).row; 
} 

-(int)columnAtIndex:(int)index { 
    return ((MyObject *)_backendArray[index]).column; 
} 

@end 

नीचे कैसे आप NSMutableArray उपवर्ग चाहते हैं का एक उदाहरण (या किसी भी वर्ग क्लस्टर) है फिर ऐसा करने के लिए:

MyCustomArrayClass *customArray = [[MyCustomArrayClass alloc] init]; 

// Your custom method 
int row = [customArray rowAtIndex:10]; 

// NSMutableArray method 
[customArray removeLastObject]; 

// Your custom class used just like an array !!! 
index = 20; 
MyObject *obj = customArray[index]; 

यह सब बहुत अच्छी तरह से काम करता है, स्वच्छ और वास्तव में लागू करने और उपयोग करने के लिए बहुत अच्छा है।

उम्मीद है कि यह मदद करता है।

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