方法调度中缺少哨兵

发布于 2024-12-23 13:54:03 字数 381 浏览 1 评论 0原文

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

}

谢谢。

I want to create a subclass of NSMutableArray and need to override the -initWithObjects: method.

But How to call [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"

}

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

月牙弯弯 2024-12-30 13:54:03

那么“missing sentinel”消息指的是丢失的 nil 终止。事实上,根据 font-of-all-knowledge-Wikipedia:

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

也是: Sentinel 节点,表示数据结构结束的对象
also:哨兵值,用于终止循环的值
另外:在 Bisync 等网络协议中,哨兵值指示帧的开始和结束位置

Then "missing sentinel" message refers to the missing nil termination. In fact, according to font-of-all-knowledge-Wikipedia:

The name of the nil that terminates a variable length list of parameters in Objective-C

also: Sentinel node, an object to represent the end of a data structure
also: Sentinel value, a value used to terminate a loop
also: In network protocols such as Bisync, sentinel values indicate where frames start and end

北斗星光 2024-12-30 13:54:03

你不能。正如 的文档中所述>NSArray

您可能想为您的子类实现一个初始化程序,即
适合子类管理的后备存储。 NSArray
类没有指定的初始值设定项,因此您的初始值设定项需要
只调用superinit方法。 NSArray 类采用
NSCopying、NSMutableCopying 和 NSCoding 协议;如果你想
通过复制或编码创建的您自己的自定义子类的实例,
重写这些协议中的方法。

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

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

You can't. As discussed in the documentation for NSArray:

You might want to implement an initializer for your subclass that is
suited to the backing store that the subclass is managing. The NSArray
class does not have a designated initializer, so your initializer need
only invoke the init method of super. The NSArray class adopts the
NSCopying, NSMutableCopying, and NSCoding protocols; if you want
instances of your own custom subclass created from copying or coding,
override the methods in these protocols.

So you can assign self = [super init]; and add the objects from your initialiser to the resulting object. Indeed, because of the way that NSArray is implemented, calling any -initWith… method is likely to return an instance of a different NSArray subclass.

Notice that the documentation also discusses alternatives to subclassing NSArray that may be easier, more reliable or better in some other way.

无风消散 2024-12-30 13:54:03

子类化 NSArray/NSMutableArray 不像子类化大多数类那样工作。 NSArray 是一个类簇,请参见子类化注释来自 NSArray 文档。

现在,对于您的具体问题,子类化 va_list 方法有点棘手,有多种方法可以处理这个问题。 “最安全”的方法是将您的 va_list 处理为 NSArray 并将其传递到另一个处理您想要的任何内容的方法中。另一种可移植性稍差、更黑客的方法是在堆栈上创建一个新的 va_list 列表以进行传递。

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

Subclassing NSArray/NSMutableArray doesn't work like subclassing most classes. NSArray is a class cluster, please see subclassing notes from the NSArray documentation.

Now, for your specific question, subclassing va_list methods is a bit tricky, there are a number of ways to handle this. The 'safest' would be to process your va_list into an NSArray and pass that into another method that dealt with whatever you wanted. The other, slightly less portable, slightly hackier way is to create a new va_list list on the stack to pass through.

    id __unsafe_unretained * stack = (typeof(stack))calloc(numOfObjects, sizeof(id));
    //filloutStack
    [super initWithObjects:*stack, nil];
    free(stack);
庆幸我还是我 2024-12-30 13:54:03

对 Apples Collection 类进行子类化并不是那么困难 - 如果您使用一个小技巧(另请参阅:

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

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

但是如果你添加一个 has-a 关系——或者:创建一个包装器——同时,你可以很容易地进行子类化:只需让你的自定义数组类有一个常规 NSArray 的成员即可。现在通过将调用转发到成员对象来重写其方法。我在这篇文章中展示了这个 ,我只是添加了通过特定测试的对象

但是你会看到,我没有正确实现你谈到的方法,但我提出了一个错误。原因是:该方法是可变参数方法,您可以传入可变数量的对象 - 要处理这个问题,您必须做一些工作。 cocoawithlove 有一篇很棒的文章。

为您服务- 如果使用这个有一个技巧 - 它可能看起来像

- (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;
}

Subclassing Apples Collection classes isn't that difficult — if you use a tiny trick (see also: cocoawithlove).

A subclass is a "is-a" relationship in object-orientated Design. But there are also "has-a" relationships, i.e. wrappers.

If you would try to create a subclass of NSArray by using a pure is-a relationship, I guess, it would be kind of hard, as you would have to do C-level memory management.

But if you add a has-a relationship — or: create a wrapper — at the same time, you can the subcalssing quite easily: Just make your custom array class have a member of a regular NSArray. Now override its method by forwarding the calls to the member object. I showed this in this post, where I just add objects, that pass a certain test.

But you will see, that I didn't implement the method you talked about correctly, but I raise a error. The reason is: that method is a variadic methods, that has a variable number of objects you can pass in — and to handle this, you have to to a bit of work. cocoawithlove has an great article about it.

For you — if using that has-a trick — it could look like

- (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;
}
冰葑 2024-12-30 13:54:03

尝试

self = [super initWithObjects:firstObj,nil];

Try

self = [super initWithObjects:firstObj,nil];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文