我有一個NSMutableArray對象,我想添加自定義方法。我嘗試了繼承NSMutableArray,但是當我嘗試使用count方法獲取對象的數量時,出現錯誤,指出「方法僅爲抽象類定義」。爲什麼count方法不被繼承?我應該繼承NSMutableArray類
我在其他地方讀過,如果我想使用它們,我必須將一些NSMutableArray方法導入到我的自定義類中。我只想將自定義方法添加到NSMutableArray類。那麼我應該子類化NSMutableArray,還是應該做其他的事情?
我有一個NSMutableArray對象,我想添加自定義方法。我嘗試了繼承NSMutableArray,但是當我嘗試使用count方法獲取對象的數量時,出現錯誤,指出「方法僅爲抽象類定義」。爲什麼count方法不被繼承?我應該繼承NSMutableArray類
我在其他地方讀過,如果我想使用它們,我必須將一些NSMutableArray方法導入到我的自定義類中。我只想將自定義方法添加到NSMutableArray類。那麼我應該子類化NSMutableArray,還是應該做其他的事情?
NSMutableArray
不是一個具體的類,它只是類集羣的抽象超類。 NSMutableArray
的文檔確實有關於如何子類的信息,但也強烈建議您不要!如果您對實際存儲有特殊需求,則只有子類。
A 類集羣意味着實際的類將在運行時被選中。創建的數組爲空,可能不會使用與1000個項目創建的數組相同的類。運行時可以明智地選擇要使用的實現。在實踐中NSMutableArray
將橋接CFArray
。沒有什麼需要擔心的,但是如果您在調試器中檢查陣列的類型,則可能會看到它,您永遠不會看到NSArray
,但通常是NSCFArray
。
如前所述,子類化與擴展類不一樣。 Objective-C具有類別的概念。一個類別與其他編程語言稱爲混合的類似。
比如你想在NSMutableArray
一個方便的方法來對財產的所有成員進行排序,然後在.h文件中定義的類接口如:
@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"];
如果您只是添加自定義方法,請使用NSMutableArray
上的類別。它是一個類集羣,所以實現由未記錄的子類提供。你需要提供一些方法來生成你自己的子類。但是,如果您只是添加一個類別,那麼您的自定義方法將在您的應用中在全部NSMutableArrays
上運行。
爲了便於比較,下面是我在implementing a custom NSMutableArray
subclass回寫的一個例子。
Objective-C有一種機制可以將方法添加到名爲Categories的現有類中。這樣你就不必創建你自己的子類。
現在鏈接不好。有沒有新的工程? – JohnK 2013-07-20 01:35:25
我更新了鏈接。 – 2013-07-26 15:16:45
我個人有T o同意節點忍者和佩羅洛夫,因爲從技術上講他們都有權利。其實,這並沒有多大幫助。
序言: 有在代碼許多陣列,所有到一個僅含有一種,但是不同類型的數據例如classA,classB,classC。
問題: 我可以很容易地混合數組,通過錯誤的傳遞給例如一些選擇器,因爲它們都是NSMutableArray。沒有靜態檢查,只有運行時檢查。
解決方案 - 第一嘗試:NSMutableArray裏的 製作子類,所以編譯器可以進行靜態檢查,並警告有關錯誤的數據類型。
因爲編譯器會發出警告,即使你傳遞錯誤類型-addObject或-objectAtIndex當你重載的人是好的。 這很糟糕,因爲你不能通過這種方式實例化NSMutableArray超類。
解決方案 - 第二次嘗試: 使某些類型的新(代理)類例如NSObject作爲NSMutableArray並添加類型爲NSMutableArray的類成員。
這是一件好事,因爲當你通過錯誤類型-addObject或-objectAtIndex當你重載那些你可以實例NSMutableClass和編譯器檢查。
的,壞的一面是,你需要您使用,不僅那些在課堂上的區別在於數組包含NSMutableArray中的每一個選擇超載。
結論: 當您構建一些在數組中有許多類類型的複雜代碼時,請相信我值得嘗試。簡單地通過這個編譯器向我展示了幾個我將不會識別的錯誤,直到我將在運行時面對它。甚至更糟的是,最終用戶會面對它。
從NSArray的蘋果參考,在方法重寫部分:
NSArray中的任意子類必須覆蓋原始的實例方法計數和objectAtIndex:。這些方法必須在您爲集合元素提供的後備存儲上運行。對於該後備存儲,您可以使用靜態數組,標準NSArray對象或其他數據類型或機制。您也可以選擇部分或完全覆蓋您想要提供替代實現的任何其他NSArray方法。
作爲一個方面說明,在Objective-C中,沒有實際的功能允許您將本類聲明爲抽象類,例如Java中的類。所以,他們所做的就是調用類似下面的代碼,從一些他們想要強制被子類重寫的方法中調用。實際上,他們給出了類的「抽象類」語義。
該方法定義作爲一個抽象方法,如果沒有覆蓋這引發了異常,與下面的輸出:
-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];
}
這是舊的文章,但認爲我想補充我的經驗。 @PayloW
的回答是一個很好的答案,我想回答你的問題很好,但是,沒有人真正回答你的問題倒過來,所以我會在這裏這樣做。
你應該繼承NSMutableArray(或NSArray)嗎?取決於你想要達到的目標。如果你只想添加一個方法來擴展數組的BASIC功能,比如排序,那麼@PayloW
的回答Categories
就是這樣。然而,如果你想創建一個類似數組的自定義類,那麼是的,子類化NSMutableArray
很容易。但是因爲它是一個類集羣,它並不像你期望的那樣完全子類化。通常在子類中,超級類中可用的方法可用於您的子類,或者您可以覆蓋它們。對於Class Clusters,您必須包含Super將要使用的方法,並提供一個超類的實例來包裝這些方法。
下面是你如何繼承NSMutableArray
一個例子(或任何類簇):
接口:
@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
然後像這樣使用:
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];
這一切工作非常好,是乾淨的,實際上非常酷實施和使用。
希望它有幫助。
我想評論一下,實現一個自定義類型安全的NSMutableArray子類是浪費時間。編寫這個自定義子類的時間花在編寫一些單元測試來驗證你的* actual *應用程序邏輯是合理的,而不是增加更多混亂。您的額外代碼僅僅是更多的代碼來維護,爲bug和安全缺陷添加更多攻擊向量,而不會爲最終用戶帶來任何實際益處。 – PeyloW 2010-10-06 14:28:49
@PeyloW:一個很好的理論位置,但最終會出現真實世界的代碼,其中類型安全是有用的。正如在我寫的文章中所描述的那樣,您將任何失敗都推向了注入的地步,而不是稍後的任意失誤。通過消除惡意對象替換的可能性,減少了攻擊面。 – 2010-10-06 14:54:03
@PeyloW:還有需要連接到CoreFoundation的真實世界的代碼。這關心你的可變數組實現是否實際上是一個NSMutableArray子類或別的東西;在這一點你的實現有更好的子類NSMutableArray。 – 2010-10-06 15:00:30