我想创建NSMutableArray
的子类,并且需要覆盖-initWithObjects:
方法。
但如何调用[super xxx];?
- (id) initWithObjects:(id)firstObj, ... {
[super initWithObjects:firstObj]; // Error: Missing sentinel in method dispatch
// Error: The result of a delegate init call must be immediately returned or assigned to "self"
}
感谢。
答案 0 :(得分:46)
然后“缺少哨兵”消息指的是缺少的nil终止。事实上,根据所有知识字体维基百科:
在Objective-C
中终止可变长度参数列表的nil的名称还:Sentinel节点,一个表示数据结构末尾的对象 另外:Sentinel值,用于终止循环的值 另外:在Bisync等网络协议中,标记值表示帧的开始和结束位置
答案 1 :(得分:10)
你做不到。正如the documentation for NSArray
中所述:
您可能希望为您的子类实现初始化程序 适合子类管理的后备存储。 NSArray class没有指定的初始化程序,因此初始化程序需要 仅调用
init
的{{1}}方法。 NSArray类采用了 NSCopying,NSMutableCopying和NSCoding协议;如果你想 通过复制或编码创建自己的自定义子类的实例, 覆盖这些协议中的方法。
因此,您可以指定super
并将初始化对象添加到生成的对象中。实际上,由于实现self = [super init];
的方式,调用任何NSArray
方法可能会返回不同 -initWith…
子类的实例。
请注意,该文档还讨论了子类化NSArray
的替代方法,这些方法可能更容易,更可靠或以其他方式更好。
答案 2 :(得分:2)
子类化NSArray
/ NSMutableArray
不像大多数类的子类化。 NSArray
是一个类群集,请参阅NSArray
文档中的subclassing notes。
现在,对于您的具体问题,子类化va_list
方法有点棘手,有很多方法可以解决这个问题。 “最安全”是将va_list
处理成NSArray
并将其传递到另一种处理您想要的方法。另一种稍微不那么便携,稍微粗暴的方法是在堆栈上创建一个新的va_list
列表来传递。
id __unsafe_unretained * stack = (typeof(stack))calloc(numOfObjects, sizeof(id));
//filloutStack
[super initWithObjects:*stack, nil];
free(stack);
答案 3 :(得分:2)
子类化Apples Collection类并不困难 - 如果你使用一个小技巧(参见:cocoawithlove)。
子类是面向对象设计中的“is-a”关系。但也有“有一个”的关系,即包装。
如果你试图通过使用纯is-a关系来创建NSArray的子类,我想,它会有点难,因为你必须进行C级内存管理。
但是如果你添加一个has-a关系 - 或者:创建一个包装器 - 同时,你可以很容易地进行调整:只需让你的自定义数组类有一个常规NSArray的成员。现在通过转发对成员对象的调用来覆盖其方法。我展示了这个in this post, where I just add objects, that pass a certain test。
但是你会看到,我没有实现你正确谈论的方法,但是我提出错误。原因是:该方法是一种可变方法,具有可传入的可变数量的对象 - 并且为了处理这个问题,您需要做一些工作。 cocoawithlove has an great article about it.
对于你 - 如果使用那个有技巧 - 它可能看起来像
- (id) initWithObjects:(id)firstObj, ... {
if (self = [super init]) {
_realArray = [[NSMutableArray alloc] initWithCapacity:1];
}
va_list args;
va_start(args, firstObj);
for (id obj = firstObj; obj != nil; obj = va_arg(args, id))
{
[self.realArray addObject:obj];
}
va_end(args);
return self;
}
答案 4 :(得分:-1)
尝试
self = [super initWithObjects:firstObj,nil];