找不到协议声明

Ak1*_*Ak1 59 cocoa-touch protocols objective-c

我有两个view controllers AB,他们都拥有对方作为自己的代表.

当我除了在头文件的开头和#import另一个头文件中定义协议之外什么都没做的时候,我得到两个错误 -

找不到"BDelegate"的协议声明,它在Ah(我写的地方)中显示无法找到"ADelegate"的协议声明,这是在Bh(我写的地方)中显示的

在线查看,人们早些时候写过,包含头文件的循环包含可能会导致问题.他们建议使用#include相反,或@class声明像 -

@class A
Run Code Online (Sandbox Code Playgroud)

代替

#import A.h
Run Code Online (Sandbox Code Playgroud)

#import B.h

我几乎试过这些进口的每一种组合,而且@classes,#include但仍然无法摆脱警告.此外,在线解决方案建议移动#import.m文件,但这也没有帮助.部分原因是在线解决方案有点模糊 - 如果你可以分解它会很棒.

关于可以做些什么来解决这个问题的任何建议?


- BigViewController.h -

#import "BaseViewController.h"
#include "BaseViewController.h"

@class BigViewController;

@protocol BigViewControllerDelegate
-(void) BigViewController:(BigViewController *) bigView;
@end

@interface BigViewController : UIViewController <BaseViewControllerDelegate>
{    
     //delegate
     id <BigViewControllerDelegate> delegate;

ivars...    
}

@properties...
@end

--------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

- BaseViewController.h -

#<UIKit/UIKit.h>

#import "BigViewController.h"
#include "BigViewController.h"

@class BigViewController;

@protocol BaseViewControllerDelegate
- (void) setParametersWithItemChosen:(Item *) item;
@end

@interface BaseViewController : UIViewController <...BigViewControllerDelegate...>
{

   ivars...

   //delegate
    id <BaseViewControllerDelegate> delegate;
}

@properties...
@end
Run Code Online (Sandbox Code Playgroud)

Ano*_*mie 101

让我进一步减少样本,并标记线条:

VC1.h

#import "VC2.h"  // A

@class VC1;

@protocol VC1Delegate // B
@end

@interface VC1 : UIViewController <VC2Delegate> // C
@end
Run Code Online (Sandbox Code Playgroud)

VC2.h

#import "VC1.h"  // D

@class VC2;

@protocol VC2Delegate // E
@end

@interface VC2 : UIViewController <VC1Delegate> // F
@end
Run Code Online (Sandbox Code Playgroud)

考虑当#imports VC1.h:它到达A行时会发生什么,然后处理导入.D行无效,因为VC1.h已经导入.然后处理E行.然后是F行,我们得到一个错误,因为我们还没有到达B行,所以没有声明协议!

然后考虑一下#imports VC2.h会发生什么:它到达D行,然后处理导入.A行无效,因为VC2.h已经导入.然后处理B行.然后是C行,我们得到一个错误,因为我们还没有得到E行,所以没有声明协议!

第一步是重新考虑这两个类是否真的需要成为彼此的代表.如果你能打破这个循环,那可能就是你要走的路.如果没有,您需要重新构建标题.最直接的方法可能是将委托放入自己的标题中:

VC1Delegate.h

@class VC1;

@protocol VC1Delegate // B
@end
Run Code Online (Sandbox Code Playgroud)

VC1.h

#import "VC1Delegate.h"
#import "VC2Delegate.h"

@interface VC1 : UIViewController <VC2Delegate> // C
@end
Run Code Online (Sandbox Code Playgroud)

VC2Delegate.h

@class VC2;

@protocol VC2Delegate // E
@end
Run Code Online (Sandbox Code Playgroud)

VC2.h

#import "VC1Delegate.h"
#import "VC2Delegate.h"

@interface VC2 : UIViewController <VC1Delegate> // F
@end
Run Code Online (Sandbox Code Playgroud)

如果现在跟踪导入,您将看到在@interface行尝试使用它们之前,现在将始终声明相应的协议.

  • 谢谢你这个优秀的解释!对于任何想要一些关于如何与Storyboard,SplitViews等相关的明确书面示例的人...... Tim Roadley在www.timroadley.com上有一些很棒的教程(我认为这是正确的地址......).我从那些页面被引导到这里. (4认同)

Vin*_*ner 101

在#import行上面写协议声明代码,例如

@协议 - - -

@结束

进口----

@interface classname ---

  • thanx ...它对我有用..但我不知道怎么做.你能解释清楚吗? (3认同)
  • 如果时间允许,请阅读Anomie的答案,以进一步解释可能发生的情况.将协议放在导入之上确保在评估导入之前定义协议.此问题类似于循环类依赖项.强烈建议Anomie建议将您的代表分成他们自己的文件. (3认同)

小智 37

我有几乎相同的问题,由于上面的答案,我修复了它,但方式略有不同.

我所做的只是将#import行放在头文件中的协议声明之后.希望我能帮忙.如果有人知道由于某种原因这是不好的编程,请告诉我

  • 在阅读了其他答案之后,我给了这个想法一个机会.当两个标头相互导入时,它似乎会创建一个循环导入.在带有协议的标头中,移动调用协议声明下方的协议的头的导入是一个完美的修复. (2认同)

Pot*_*las 10

我找到了另一个解决这个问题的方法,因为我真的不喜欢在类和协议声明之间只有一些#imports的想法.

基本上你只是<YourProtocolName>从.h类文件移动到.m文件中的类扩展名

所以在你的.m文件中添加

@interface YourClassName () <YourProtocolName>
@end
Run Code Online (Sandbox Code Playgroud)

我不知道这是不是一个好的做法,但它看起来像一个更清洁的解决方案,以避免导入周期.


cor*_*iOS 8

尝试将<BaseViewControllerDelegate>或<BigViewControllerDelegate>放在实现文件中,而不是头文件中.它会工作.