Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 级联代表和;不使用';“不要照它说的去做”;_Objective C_Cocoa_Xcode_Delegation - Fatal编程技术网

Objective c 级联代表和;不使用';“不要照它说的去做”;

Objective c 级联代表和;不使用';“不要照它说的去做”;,objective-c,cocoa,xcode,delegation,Objective C,Cocoa,Xcode,Delegation,我一直在苹果公司的代表团和协议文档中寻找答案,但一天多之后,我决定放弃,让你们尝试一下。我有三个类:HTTPManager、LoginManager和FetchManager。您可能会猜到这些类的作用,但要明确地说 HTTPManager-包装了NSURLConnection,并为LoginManager和FetchManager提供了一个简单的接口,用于通过身份验证执行HTTP请求 LoginManager/FetchManager-基本上是同一个类,但它们对HTTPManager消息的响应

我一直在苹果公司的代表团和协议文档中寻找答案,但一天多之后,我决定放弃,让你们尝试一下。我有三个类:HTTPManager、LoginManager和FetchManager。您可能会猜到这些类的作用,但要明确地说

  • HTTPManager-包装了NSURLConnection,并为LoginManager和FetchManager提供了一个简单的接口,用于通过身份验证执行HTTP请求
  • LoginManager/FetchManager-基本上是同一个类,但它们对HTTPManager消息的响应不同
HTTPManager需要一个委托来实现HTTPManagerDelegate协议,LoginManager和FetchManager都会这样做。Login-and-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*
?没有继承,我的返回类型是正确的,所以对我来说,这是一些黑暗形式的伏都教,我不能最好

这是我的应用程序的外壳。可能存在拼写错误和小的不一致,因此在假设语法问题之前,请询问我:

// 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;
}

...
//HTTPManager.h
@协议HTTPManagerDelegate
...
@结束
@接口HTTPManager:NSObject
{
身份证代表;
...
}
-(HTTPManager*)initWithDelegate:(id)delegate;
...
@结束
//LoginManager.h
@协议LoginManagerDelegate
...
@结束
@接口登录管理器:NSObject
{
身份证代表;
...
}
-(LoginManager*)initWithDelegate:(id)delegate;
...
@结束
//MyAppDelegate.h
@接口MyAppDelegate:NSObject
{
LoginManager*\u loginMgr;
...
}
...
@结束
//MyAppDelegate.m
...
-(MyAppDelegate*)初始化
{
self=[super init];
如果(自我)
{
//警告发生在这里
_loginMgr=[[LoginManager alloc]initWithDelegate:self];
...
}
回归自我;
}
...

提前感谢。

问题是您有两个方法具有相同的方法签名
-initWithDelegate:
,但其参数和/或返回类型不同。编译器无法很好地处理这种情况,在某些情况下,它还可能导致运行时出错(在您的情况下不是这样,因为方法中的类型大小不一样,它们都是指针)

原因是(AFAIK)运行时无法直接访问方法中使用的类型。它只读取一个选择器(不包含类型信息),并根据该选择器决定调用哪个方法。为了帮助运行时将方法参数打包到堆栈中,编译器在编译时创建一个表,将选择器映射到参数和返回值类型。此表中每个选择器只有一个条目。因此,如果存在两个具有相同选择器但参数或返回值类型不同的方法,则此系统可能会失败

就你而言:

-init…
方法应始终返回
id
,而不是特定类型

这就解决了不同退货类型的问题。另一个问题(不同的参数类型)更难解决。您可以从方法声明中省略协议规范(
initWithDelegate:(id)delegate
),或者为这两个方法指定不同的名称:

- (id) initWithHttpMgrDelegate:(id <HTTPManagerDelegate>)delegate;
- (id) initWithLoginMgrDelegate:(id <LoginManagerDelegate>)delegate;
-(id)initwithhttpmgrrdelegate:(id)delegate;
-(id)initWithLoginMgrDelegate:(id)delegate;

实际上,编译器可以从接收者的类型推断出正确的方法签名——如果接收者是静态类型的,也就是说。这里的问题是
alloc
返回
id
,因此编译器没有可处理的信息。谢谢!这回答了我所有的问题和更多。我不明白为什么它。。。应该返回id。如果它返回一个更具体的类型,它只会在编译时导致更好的类型检查,在运行时不会有任何区别,对吗?