我一直在寻找Apple的代表团和协议文档来寻找答案,但经过一天多的努力,我决定放弃,让你们有机会接受它。我有三个类:HTTPManager,LoginManager和FetchManager。您可以猜测这些类的作用,但要明确......
HTTPManager期望委托实现HTTPManagerDelegate协议,LoginManager和FetchManager都执行此操作。 Login-和FetchManager类还为我的应用程序委托提供协议,以便数据可以一直回到用户界面。
在我的应用程序委托的init:
方法中,我初始化了登录和获取管理器,并为两者获取以下警告:
warning: class 'MyAppDelegate' does not implement the 'HTTPManagerDelegate' protocol
warning: incompatible Objective-C types assigning 'struct HTTPManager *', expected 'struct LoginManager *'
初始化的两个类都不是从HTTPManager派生的,但它们确实实现了HTTPManagerDelegate协议。产生上述警告的代码行是:
_loginMgr = [[LoginManager alloc] initWithDelegate:self];
那么究竟是什么让LoginManager的initWithDelegate:
方法返回HTTPManager*
?没有继承,我的返回类型是正确的,所以对我来说这是一些我不能最好的黑暗巫术。
这是我的应用程序的shell。可能存在拼写错误和小的不一致,所以在假设语法问题之前请问我:
// HTTPManager.h
@protocol HTTPManagerDelegate
...
@end
@interface HTTPManager : NSObject
{
id <HTTPManagerDelegate> _delegate;
...
}
- (HTTPManager *) initWithDelegate:(id <HTTPManagerDelegate>)delegate;
...
@end
// LoginManager.h
@protocol LoginManagerDelegate
...
@end
@interface LoginManager : NSObject <HTTPManagerDelegate>
{
id <LoginManagerDelegate> _delegate;
...
}
- (LoginManager *) initWithDelegate:(id <LoginManagerDelegate>)delegate;
...
@end
// MyAppDelegate.h
@interface MyAppDelegate : NSObject <NSApplicationDelegate, LoginManagerDelegate, FetchManagerDelegate>
{
LoginManager *_loginMgr;
...
}
...
@end
// MyAppDelegate.m
...
- (MyAppDelegate *) init
{
self = [super init];
if (self)
{
// WARNING HAPPENS HERE
_loginMgr = [[LoginManager alloc] initWithDelegate:self];
...
}
return self;
}
...
提前致谢。
答案 0 :(得分:3)
问题是你有两个方法具有相同的方法签名-initWithDelegate:
但在它们的参数和/或返回类型中有不同的类型。编译器无法很好地处理这种情况,在某些情况下,它也可能在运行时导致错误(不是因为你的方法中的类型大小不同,它们都是指针)。
原因(AFAIK)是运行时无法直接访问方法中使用的类型。它只读取一个选择器(不包含类型信息)并根据此选择器决定调用哪种方法。为了帮助运行时将方法参数打包到堆栈中,编译器在编译时创建一个表,将选择器映射到参数和返回值类型。该表每个选择器只有一个条目。因此,如果存在两个具有相同选择器但参数或返回值类型不同的方法,则此系统可能会失败。
在你的情况下:
-init...
方法应始终返回id
而不是特定类型。
这解决了不同返回类型的问题。另一个问题(不同的参数类型)更难解决。您可以从方法声明(initWithDelegate:(id)delegate
)中省略协议规范,或者为这两种方法指定不同的名称:
- (id) initWithHttpMgrDelegate:(id <HTTPManagerDelegate>)delegate;
- (id) initWithLoginMgrDelegate:(id <LoginManagerDelegate>)delegate;