我正在使用一个框架来定义和使用'ClassA',它是NSObject的子类。我想添加一些变量和功能,所以我自然创建了'ClassB','ClassA'的子类
现在我的问题是这个。这个框架中的许多方法返回'ClassA'的实例,我想将它转换为我的子类。
例如采用这种方法:
- (ClassA *)doSomethingCool:(int)howCool
现在在我的代码中我试试这个:
ClassB * objB;
objB = (ClassB *)doSomethingCool(10);
NSLog(@"objB className = %@", [objB className]);
运行得很好。没有编译或运行时错误或任何东西。但对我来说真正奇怪的是输出:
>> "objB className = ClassA"
铸造显然失败了。不知道此时发生了什么...... objB被输入为'ClassB',但它的className是'ClassA',它不会响应任何'ClassB'方法。
不确定这是怎么可能的......任何人都知道我在做错了什么?
我发现了一个类似的帖子,与我提出的here
完全相反答案 0 :(得分:26)
在Objective-C中转换对象变量通常是一个错误(有些情况下它是正确的,但从来没有这样的事情)。请注意,您没有投射对象 - 您正在向对象投射指针。然后,您有一个类型为ClassB*
的指针,但它仍然指向ClassA的同一个实例。指出的事情根本没有改变。
如果您真的想将ClassA的实例转换为ClassB,则需要编写一个可以从ClassA创建ClassB实例的ClassB构造函数方法。如果您确实需要添加实例变量,这可能是您的最佳选择。
正如Jason所说,首先尝试一个类别通常是一个好主意。
答案 1 :(得分:19)
你不能只将超类强制转换为它的子类。它实际上并没有实现任何添加的变量/属性或方法。只要您尝试使用在子类上定义的方法对其进行消息传递,您将获得运行时异常,并且您的应用程序将要退出。你只能安全地向一个方向施展:从更具体到更一般。即,您可以使用ClassA的方法和属性安全地将ClassB转换为ClassA,但不能反过来。
可以这样想:你有一个Car(父类)和一个FourDoorSedan(子类)。每辆车都有一个发动机和两扇门。现在,假设你从某个地方买了一辆车,那就是你所知道的。你告诉接线员,这辆车是FourDoorSedan,但实际上事实证明并非如此。因此,当运营商做类似的事情时:openBackPassengerDoor,会发生什么?只有两扇门!这里也一样。
如果您只想向ClassA添加一些功能,请查看Objective-C类别,它们可能就是您想要的,并且不需要任何转换。但请仔细阅读文档,因为它们并非没有警告。
答案 2 :(得分:5)
如果您只想向现有对象添加方法,则子类化不是正确的方法。您可以使用名为category的语言功能将方法添加到现有类(及其实例)。
示例:
//"ClassA+doSomethingCool.h"
@interface ClassA (doSomethingCool)
- (ClassA *)doSomethingCool:(int)howCool;
@end
//"ClassA+doSomethingCool.m"
@implementation ClassA (doSomethingCool)
- (ClassA *)doSomethingCool:(int)howCool
{
}
@end
答案 3 :(得分:2)
Casting不会从一种类型的对象转换为另一种类型的对象。除非使用某种工厂模式,否则不能强制某些库更改对象类型并创建其他类型的对象。
答案 4 :(得分:0)
当您在返回的对象上调用其中一个子类方法时会发生什么?
ClassB * objB;
objB = (ClassB *)doSomethingCool(10);
[objB subClassMethod];
Obj-C非常自由而且输入类型,你甚至不需要事先知道类型,例如。您可以将所有ClassB引用更改为id。 我知道知道你有预期的类型更安全,但如果你的代码是正确的,那就不重要了。