方法调度中缺少哨兵

时间:2012-01-02 17:10:38

标签: objective-c cocoa nsarray subclass

我想创建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"

}

感谢。

5 个答案:

答案 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];