在类型为超类的变量上调用子类方法

时间:2011-12-13 17:08:57

标签: objective-c types subclassing message-passing

我创建了一个名为Foo的小组:

@interface Foo:NSObject{
     int myInt;
}
@property int myInt;
@end

以及名为Foo的{​​{1}}的子类:

Bar

我正在尝试将@interface Bar:Foo{ NSString *myString; } @property (copy) NSString *myString; @end 存储为数组中的Bar对象,如下所示:

Foo

我这样做是因为我实际上有-(void)createBar{ Foo *object = [[Bar alloc]init]; // myArray is an instance of NSMutableArray [myArray addObject:object]; } 的多个子类(我不想全部列出)。当我从数组中获取对象并将消息发送到对象以获取Foo变量时,应用程序不执行任何操作。 示例:

myString

我是否误解了'信息'是如何运作的?我假设我可以向对象发送消息,无论是否存在,它都会调用它。我需要以其他方式做这件事吗?该数组将包含所有不同类型的-(NSString *)getStringFromFooAtIndex(NSUInteger)index{ Foo *object = [myArray objectAtIndex:index]; return [object myString]; } 子类,我需要它来存储它们。

3 个答案:

答案 0 :(得分:3)

  

我假设我可以向对象发送消息,无论是否存在,都会调用它。

您确实可以向任何对象发送任何消息;这是Objective-C乐趣的一部分。 变量的类型Foo *Bar *id或其他任何内容)对邮件发送无效。变量点知道其类的对象。相应方法的查找是在运行时通过该类完成的。编译器将括号中的表达式转换为对函数objc_msgSend的调用。

你应该在构建时收到关于[object myString]的警告,说“'Foo'可能不响应'myString'” - 编译器知道至少有一个类的某个地方有一个对应于{的方法{1}},它知道在编译时,myString似乎不是其中之一,但它不能保证Foo无法做到在运行时与消息的东西。消息可以解析in custom ways during runtime。请注意,如果将变量的类型更改为Foo,警告将消失 - 编译器无法再推断可用的方法。

如果事实证明您发送的id 对象没有响应(即,如果对象确实是 a {{1} }而不是myStringFoo的一个未实现Bar的子类,将引发异常。这是默认响应(通过从Foo继承的任何内容)到无法识别的消息。

如果您有需要发送消息的异构对象集合,则可能需要先测试每个对象。你可以像jstevenco建议的那样做,并测试功能性:

myString

或测试身份:

NSObject

如果对象是if( [object respondsToSelector:@selector(myString)] ){ 或任何if( [object isKindOfClass:[Bar class]] ){ 的子类,后者将通过。使用Bar仅测试您指定的类。

答案 1 :(得分:1)

有关如何处理消息传递逻辑的详细摘要,请参阅here。如果您不覆盖-(void)doesNotRecognizeSelector:(SEL)aSelector,最终会产生错误。

如果您要拥有多态对象集合,则应首先使用respondsToSelector:测试该对象,然后根据需要直接调用该方法或使用performSelector:变体之一。另一种可能性是在基类中包含myString的实现,它不执行任何操作。

答案 2 :(得分:0)

我弄清楚问题是什么。

在我的AppDelegate.m文件中,我有以下方法:

- (void)createFoo{
     Foo *foo = [[Bar alloc]init];

     [myArrayController add:foo];
}

这是将'foo'对象插入我的数组控制器。我也定义了这个方法:

- (void) insertObject:(Foo *)object intoMyArrayControllerAtIndex:(NSUInteger)index{
     // handles the inserting of the object as well as working with the undo manager
}

现在,调用[myArrayController add:foo]是造成问题的原因。如果我用[self insertObect:foo intoMyArrayControllerAtIndex:0]替换该行,那么一切都很完美。

非常感谢你,对不起浪费你的时间。