Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

russell.h

macrumors regular
Original poster
Jul 2, 2007
112
0
So I have this Class called "LibraryItem". It basically needs to store a mutable array along with a few strings.

So I declared it like so:
Code:
@interface LibraryItem : NSMutableArray {
	NSString *itemType;
	NSString *itemPath;
}

- (id)initWithType:(NSString *)itemTypeToSet Path:(NSString *)path;
- (void)setItemType:(NSString *)newType;
- (void)setItemPath:(NSString *)newPath;
- (NSString *)getItemType;
- (NSString *)getItemPath;

@end
But when I call the "count" method the console shows:
Code:
*** -[NSArray count]: method only defined for abstract class.  Define -[LibraryItem count]!

Am I doing something wrong? Thanks,

Russell
 

HexMonkey

Administrator emeritus
Feb 5, 2004
2,240
504
New Zealand
NSArray and NSMutableArray are part of a class cluster so can't easily be subclassed. From the NSArray documentation:

NSArray and NSMutableArray are part of a class cluster, so arrays are not actual instances of the NSArray or NSMutableArray classes but of one of their private subclasses. Although an array’s class is private, its interface is public, as declared by these abstract superclasses, NSArray and NSMutableArray.

More information on class clusters is available here.

From a design perspective, however, your class should contain an array, not inherit it. What you are doing is known as inheritance for implementation, which means that you're inheriting a class for implementation purposes, not because it makes logical sense. By inheriting NSMutableArray, you're basically stating that LibraryItem is an array (which logically it isn't), and you're making it significantly more difficult to change your code in the future should you decide to change the way you store the list (for example, if you were to change it to use an NSMutableSet instead then you'd have to change every class that uses LibraryItem, rather than just the LibraryItem class).

Another problem is that other classes could use LibraryItem in unexpected ways by using methods in NSMutableArray that you don't anticipate - an example of this problem is the Java API where Stack inherits Vector; this lets you, for example, remove an item from midway through the stack, which violates the rules of a stack.
 

iSee

macrumors 68040
Oct 25, 2004
3,539
272
A general rule of thumb when deciding between inheritence and containment to represent the relationship between two objects is this:

Inheritence = is a
Containment (member) = has a

So, you just say/write/think the relationship and pick the one that makes sense:

1. LibraryItem is an array
2. LibraryItem has an array

So in this case, #2 is the obvious choice.

Actually, in the case of inheritance, it's better to say the relationship in a stronger way:

Every <class 1> is a <class 2>.

This will help you catch certain object model errors. (If the statement isn't true, you shouldn't try to represent the relationship as class 1 inherits from class 2.)
 

col.

macrumors newbie
Jun 24, 2008
2
0
But I really like sub-classing NSMutableDictionary :(

I've just come across the same problem. It had me very confused but I found this thread and it explained the situation very well so thank you.

However, I'm not so sure what I'm trying to do is a bad thing and I'd like to know if there IS a way for me to extend an NSMutableDictionary.

I'm a Java WebObjects programmer that has been subclassing NSMutableDictionary for years and have found it extremely useful. Basically I find it to be a great way to create an class and to store any instance variables I like by calling setObjectForKey. Doing this has a lot of advantages such as:
- it automatically provides key value coding
- it automatically provides serialization and de-serialization in multiple formats
- I can dynamically add properties to the object whenever I want
- etc. etc.

I'm now starting to do more and more Objective-C programming and would like to continue to subclass NSMutableDictionary when appropriate.

I'm not experienced in Objective-C yet to figure out a way around the problem mentioned above. Does anyone have any advice as too weather this can be done or not?? and if so how?

thanks
 

Catfish_Man

macrumors 68030
Sep 13, 2001
2,579
2
Portland, OR
Basically what you'd need to do is figure out which methods on NSMutableDictionary are its "primitive" methods (check the header file), and which ones are implemented in categories. Then have your subclass provide its own implementations of all the primitive methods, and the ones from categories should just work.
 

adobongkangkong

macrumors newbie
Aug 26, 2008
2
0
Subclassing NSMutableDictionary

@ col.

Hi col. this is a bit off topic but this question is for you. You said you're a WebObjects programmer and have been subclassing dictionary I just want to know how did you subclass NSMutableDictionary. I have been subclassing NSMutableDictionary but everytime I use WOXMLCoder to serialize a subclass of NSMutableDictioanry it all resulst to its immutable counter part which is NSDictionary.

e.g.: I have a class MyDictionary that extends NSMutableDictionary.
My MyDictionary has the following methods.

setUserName(String username){
this.setObjectForKey(username,"USERNAME");
}

userName(){
if(this.containsKey("USERNAME")){
return (String)this.objectForKey("USERNAME");
}else{
return new String();
}
}

And when I serialized MyDictionary object using WOXMlCoder the result is this.

<ROOT type="com.webobjects.foundation.NSDictionary" objectID="1">
<USERNAME type="java.lang.String" objectID="2">myusername</USERNAME>
</ROOT>

Notice that the type of the ROOT document is "com.webobjects.foundation.NSDictionary" why not "MyDictionary" or "NSMutableDictionary" why "NSDictionary" ?

Please reply to this post and thanks in advance.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
@ col.

Hi col. this is a bit off topic but this question is for you. You said you're a WebObjects programmer and have been subclassing dictionary I just want to know how did you subclass NSMutableDictionary. I have been subclassing NSMutableDictionary but everytime I use WOXMLCoder to serialize a subclass of NSMutableDictioanry it all resulst to its immutable counter part which is NSDictionary.

e.g.: I have a class MyDictionary that extends NSMutableDictionary.
My MyDictionary has the following methods.

setUserName(String username){
this.setObjectForKey(username,"USERNAME");
}

userName(){
if(this.containsKey("USERNAME")){
return (String)this.objectForKey("USERNAME");
}else{
return new String();
}
}

And when I serialized MyDictionary object using WOXMlCoder the result is this.

<ROOT type="com.webobjects.foundation.NSDictionary" objectID="1">
<USERNAME type="java.lang.String" objectID="2">myusername</USERNAME>
</ROOT>

Notice that the type of the ROOT document is "com.webobjects.foundation.NSDictionary" why not "MyDictionary" or "NSMutableDictionary" why "NSDictionary" ?

Please reply to this post and thanks in advance.

This was totally off-topic, but...
http://developer.apple.com/document...bobjects/appserver/xml/WOXMLCoder.html#coder()

"an instance of NSArray, NSDictionary and NSData. Please note that before WebObjects 5.1, when the mutable forms of these classes (NSMutableArray, NSMutableDictionary and NSMutableData) are encoded using WOXMLCoder, they get written out as their immutable counterparts. For example, NSMutableArray used to be written out as NSArray. Now, they get written out as themselves. As a result, when WOXMLDecoder is used to decode the objects, they are decoded as mutable forms."

If you are using WebObjects less than 5.1, it looks like this is known behavior.

If you can't get around this behavior, you should be able to get yourself an NSMutableDictionary from the decoded NSDictionary with:

http://developer.apple.com/document...ionary(com.webobjects.foundation.NSDictionary)

-Lee
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.