Objective-C继承方法匹配
我遇到过一个与 Objective-C 中的类继承相关的奇怪场景。
假设我有三个类 A、B 和 C,它们从基类 X 继承。类 A、B 和 X 具有构造函数:
- (id)InitWithString:(NSString*)someString andDelegate:(id<SomeProtocol>)aDelegate
唯一的区别是每个类对委托使用不同的协议。
所发生的情况是,对于 A 和 B,编译器尝试使用 C 中的方法。一条警告通知我,所提供的委托未实现类 C 的构造函数所需的协议。委托本身没有任何问题,因为每个类都有一个为类自己的构造函数实现正确协议的委托。运行时一切正常,并且为所有类调用正确的函数。
我尝试让构造函数返回 A*、B* 或 C* 而不是匿名 id,但这仍然不能解决问题。
唯一有效的方法就是像这样对正确的类进行强制转换:
instanceOfA = [(A*)[A alloc] InitWithString:@"" andDelegate:aDelegate];
这似乎是多余且不必要的。我可能在这里遗漏了一些明显的东西。
I've come across a strange scenario related to class inheritance in Objective-C.
Let's say i have three classes A, B and C that inherit from a base class X. Classes A, B and X have the constructor:
- (id)InitWithString:(NSString*)someString andDelegate:(id<SomeProtocol>)aDelegate
the only difference being that every class uses a different protocol for the delegate.
What happens is that for A and B the compiler tries to use the method from C. A warning informs me that the protocols required by class C's constructor is not implemented by the provided delegate. There is nothing wrong with the delegate itself, since each class has a delegate that implements the right protocol for the classes' own constructor. Everything works fine at run time and the right functions are called for all classes.
I tried having the constructors return A*, B* or C* instead of the anonymous id, though this still doesn't solve the problem.
The only thing that works is making a cast to the right class like this:
instanceOfA = [(A*)[A alloc] InitWithString:@"" andDelegate:aDelegate];
This seems superfluous and unnecessary. I'm probably missing something obvious here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不确定分析器对于这些情况实际上有多聪明,并且怀疑您只是遇到了它的局限性之一。
您所观察到的是编译器将对象视为 id 并选择与签名匹配的第一个方法。尝试移动包含类的顺序,您应该看到它总是选择首先定义的选择器。
解决这个问题的一种方法是分两步初始化类:
在这种情况下,分析器知道测试是 ClassA 类型并选择正确的选择器。似乎它并不聪明,无法判断未分配给变量的中间对象是什么类型,然后总是假设它们是
id
。I'm not sure how clever the analyzer actually is for these cases and suspect you simply hit one of its limitations.
What you're observing is the compiler seeing the object as
id
and picking the first method that matches the signature. Try moving the order you including your classes around and you should see that it always picks the selector that gets defined first.A way to get around this is to initialize the class in two steps:
In this case, the analyzer knows test is of type ClassA and picks the right selector. It seems that it's not so clever as to tell of what type intermediary objects are that are not assigned to a variable and then just always assumes them to be
id
.问题在于定义指定类型参数的方法的声明。
您应该使声明尽可能通用,以便对作为最后一个参数传递的对象的所有类都有效。
如果所有协议都继承自父协议,则可以将该方法声明为
- (id)initWithString:(NSString*)someString andDelegate:(id)aDelegate
;不同的是,您可以使用更通用的定义- (id)initWithString:(NSString*)someString andDelegate:(id)aDelegate
The problem is with the declaration of the method which defines a parameter of a specified type.
You should make the declaration as generic as possible to be valid for all the classes of the object passed as last parameters.
if all the protocol inherit from a parent protocol, then you can declare the method as
- (id)initWithString:(NSString*)someString andDelegate:(id<ParentProtocol>)aDelegate
; differently, you can use the more generic definition- (id)initWithString:(NSString*)someString andDelegate:(id)aDelegate