Objective c 方法调度中缺少哨兵

Objective c 方法调度中缺少哨兵,objective-c,cocoa,nsarray,subclass,Objective C,Cocoa,Nsarray,Subclass,我想创建NSMutableArray的子类,需要重写-initWithObjects:方法 但是如何称呼[超级xxx] - (id) initWithObjects:(id)firstObj, ... { [super initWithObjects:firstObj]; // Error: Missing sentinel in method dispatch // Error: The result of a delegate init call must be immedi

我想创建
NSMutableArray
的子类,需要重写
-initWithObjects:
方法

但是如何称呼[超级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"

}
谢谢。

试试看

self = [super initWithObjects:firstObj,nil];

你不能。如中所述:

您可能希望为您的子类实现一个初始值设定项,即 适用于子类正在管理的备份存储。安萨里酒店 类没有指定的初始值设定项,因此您的初始值设定项需要 仅调用
super
init
方法。NSArray类采用 NSCopying、NSMutableCopying和NSCoding协议;如果你愿意 通过复制或编码创建的自定义子类的实例, 重写这些协议中的方法

因此您可以分配
self=[super init]
并将初始化器中的对象添加到结果对象中。实际上,由于
NSArray
的实现方式,调用任何
-initWith…
方法都可能返回不同
NSArray
子类的实例


请注意,本文档还讨论了子类化
NSArray
的替代方法,这些方法可能更简单、更可靠或在其他方面更好。

子类化
NSArray
/
NSMutableArray
与子类化大多数类不同
NSArray
是一个类群集,请参阅
NSArray
文档

现在,对于您的特定问题,子类化
va_list
方法有点棘手,有很多方法可以处理这个问题。最安全的方法是将你的
va_列表
处理成一个
NSArray
并将其传递到另一个方法中,该方法可以处理你想要的任何事情。另一种稍微不那么便携、稍显粗糙的方法是在堆栈上创建一个新的
va_列表
list来传递

    id __unsafe_unretained * stack = (typeof(stack))calloc(numOfObjects, sizeof(id));
    //filloutStack
    [super initWithObjects:*stack, nil];
    free(stack);

对Apple集合类进行子类化并不困难——如果您使用一个小技巧(另请参见:)

在面向对象的设计中,子类是一种“is-A”关系。但也有“has-a”关系,即包装器

如果您试图通过使用纯is-a关系来创建NSArray的子类,我想,这会有点困难,因为您必须进行C级内存管理

但是,如果同时添加has-a关系或:创建包装器,则可以非常轻松地进行子封装:只需使自定义数组类具有常规NSArray的成员即可。现在,通过将调用转发到成员对象来覆盖其方法。我展示了这个

但是您将看到,我没有正确地实现您提到的方法,但是我提出了一个错误。原因是:这个方法是一个可变的方法,它有一个可变数量的对象,你可以传入-要处理这个问题,你需要做一些工作

对你来说,如果使用它有一个技巧,它可能看起来像

- (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;
}
然后,“missing sentinel”消息指的是丢失的nil终止。事实上,根据维基百科所有知识的字体:

在Objective-C中终止可变长度参数列表的nil的名称

另外:Sentinel节点,表示数据结构结尾的对象 另外:Sentinel值,用于终止循环的值
另外:在网络协议(如Bisync)中,sentinel值指示帧的开始和结束位置

您解决了委托问题,但仍然存在缺少sentinel的警告…我尝试了
self=[super initWithObjects:firstObj,nil]和警告消失,但调用此子类时数组中的对象是否会丢失?是的,很抱歉,您必须在末尾添加nil。对不起,我不明白你的问题…@BenLu:请看jlehr的答案和我对它的评论。这会起作用,但它只会(尝试)用第一个对象初始化数组,而不会初始化任何其他对象。不管传递了多少个对象,充其量只能得到一个包含不超过一个对象的数组。