【问题标题】:How to treat NSArray of mixed content as of unified content?如何将混合内容的 NSArray 视为统一内容?
【发布时间】:2014-03-10 06:49:40
【问题描述】:

B 类派生自 A 类。 B类覆盖'-(NSString *)描述',在A类中也被覆盖。 我创建了一个新的“NSArray”指向实例的指针,包括 A 类和 B 类。

是否可以将一个循环中的所有这些实例都视为 A 类实例,更准确地说 - 是否可以对所有这些实例使用 A 类“- (NSString *) 描述”?

目前,我使用检查它是否是 B 类实例,并在这种情况下调用生成 A 类实例的初始化程序。但这似乎没有必要,我不喜欢这种解决方案。

【问题讨论】:

  • 不,这是不可能的。你为什么要这样做?你更大的目标是什么?
  • 我想获取上下文描述。比如说,Class Worker 派生自 Class Person。如果我召集工人问他们“你们是谁,伙计们?”,我希望他们告诉我他们的工作是什么。但是,如果我同时收集 Persons 和 Workers 并提出相同的问题,我期望的只是名称。

标签: objective-c nsarray


【解决方案1】:

是的,你可以做到。

for (ClassA item in myMixedArray)
    NSLog("@%", item.description);

如果myMixedArray 具有 ClassA、ClassB 的元素,则此方法有效。事实上(尽管不正确且非常混乱)它适用于任何类或对象指针,即使它们与 A 类或 B 类无关。唯一的问题是确保 item 实现 description,否则它将失败。

在您的具体情况下,它非常安全,因为任何元素都会以某种方式成为 ClassA 对象(直接或继承)。

如果有一天您需要拥有完全不相关的对象,您可以使用 id 作为迭代器类型。

for (id item in myMixedArray)
    [id someMethodThatAllObjectsImplement];

编辑(澄清误解的问题):
在 Objective-C 中,没有简单的方法来强制调用基类实现,与 C++ 不同,即使类型转换指针也将被证明是无用的。有一种棘手的方法可以强制调用this question 上解释的基类实现。

【讨论】:

  • 这不起作用——在这种情况下,由于某种原因,如果它是 B 类的实例,它将被称为描述:来自 B 类。
  • @explogeek 是的,这是正确的。我所说的任何元素都会以某种方式成为ClassA对象的意思是澄清使用ClassA作为迭代器对象是正确的,但如果对象是ClassB,那么它将调用@987654331 @ 的实现。
  • 但我在主题中的问题是关于忽略该实现 - 这就是我感兴趣的。
  • 第一部分没有解决问题,第二部分确实调用了超类的方法,但是如果我把C类从B类派生出来就不行了,还需要额外的检查。如果需要检查,那么我的“解决方案”(在问题主题的末尾)更合适,因为它适用于任何级别的派生。
  • 我不确定你的解决方案会不会很好。你试图做的事情违背了继承的目的。我认为您应该重新考虑使用名为 baseDescription (或其他)的第二个属性或方法来强制调用基类描述。
【解决方案2】:

下面的例子可能比 Merlevede 的回答中提到的其他线程中的解决方案更容易一些。

for ( id item in array )
{
    if ( [item isMemberOfClass:[ClassA class]] )
    {
        NSLog( @"%@", item );
    }
    else
    {
        struct objc_super parent = { item, [item superclass] };
        NSLog( @"%@", objc_msgSendSuper( &parent, @selector(description) ) );
    }
}

objc_msgSendSuper 函数可用于调用任何返回 id 的方法

编辑 - 忘了提到你需要

#import <objc/message.h>

编辑 2 - 根据 cmets 中 OP 的反馈,这是最终解决方案

for ( id item in array )
{
    struct objc_super baseClass = { item, [ClassA class] };
    NSLog( @"%@", objc_msgSendSuper( &baseClass, @selector(description) ) );
}

【讨论】:

  • 这确实解决了它,但它不适用于派生自 B 的类。如果需要检查,那么我的“解决方案”(在问题帖子的末尾)更普遍(使用初始化器创建缓冲区 A 类实例)
  • 好的,修好了。事实证明,更通用的解决方案是更少的代码。
猜你喜欢
  • 2016-06-22
  • 2018-04-11
  • 1970-01-01
  • 2019-06-13
  • 2018-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多