问题
Here's my try:
H file:
@interface Strings : NSArray
@end
M file:
@implementation Strings
- (id) init
{
[self initWithObjects:
@"One.",
nil];
return self;
}
@end
When I run I get this:
'NSInvalidArgumentException', reason: '* -[NSArray initWithObjects:count:]: method only defined for abstract class. Define -[Strings initWithObjects:count:]!'
This is what I did instead:
H file:
@interface Strings : NSObject
+ (NSArray*) getStrings;
@end
M file:
@implementation Strings
+ (NSArray*) getStrings
{
NSArray* strings = [[NSArray alloc] initWithObjects:
@"One.",
nil];
return strings;
}
@end
回答1:
NSArray
is a class cluster (link to Apple's documentation). This means that when you try to create an NSArray
, the system creates some private subclass of NSArray
. The NSArray
class just defines an interface; subclasses of NSArray
provide implementations of the interface.
You can write your own subclass of NSArray
, but you have to provide your own storage for the objects in the array. You have to initialize that storage yourself. The error message is telling you this, by saying that you need to override initWithObjects:count:
in your subclass. Your override needs to put the objects into whatever storage you allocate as part of your class implementation.
The NSArray
implementation of the variadic initWithObjects:
method is just a wrapper around initWithObjects:count:
, so you don't have to implement initWithObjects:
.
回答2:
Deriving from NSArray
is something you should avoid. From the documentation:
Remember that NSArray is the public interface for a class cluster and what this entails for your subclass. The primitive methods of NSArray do not include any designated initializers. This means that you must provide the storage for your subclass and implement the primitive methods that directly act on that storage.
What this means is that when you initialize an array, you don't get an instance of NSArray
. You'll get an instance of a totally different class that merely has the same interface. That is why subclassing doesn't work the way you think it works: you'll have to completely implement the storage yourself. This is why the documentation further states:
Any subclass of NSArray must override the primitive instance methods count and objectAtIndex:. These methods must operate on the backing store that you provide for the elements of the collection. For this backing store you can use a static array, a standard NSArray object, or some other data type or mechanism. You may also choose to override, partially or fully, any other NSArray method for which you want to provide an alternative implementation.
Last but not least you would have had the initializing wrong anyway. You would have needed to call super
:
- (id)init
{
self = [super initWithObjects:@"One", @"Two", nil];
if (!self) return nil;
return self;
}
But as I just said, it just doesn't work that easily. You'll get the same exception again. So you should simply avoid doing deriving from NSArray
.
What you can do is add a category to add methods to all NSArray
instances.
回答3:
NSArray doesn't support being subclassed in this way. You can add a category, though, although that's not universally recommended.
See Objective C - Subclassing NSArray for more thoughts.
回答4:
perhaps
self = [super initWithObjects:...];
回答5:
You need to assign self, and call your superclass' init method.
if (self = [super initWithObjects:...]) {
...
}
return self;
来源:https://stackoverflow.com/questions/8964547/how-do-i-extend-an-nsarray