Objective c 什么';在Objective C中,确保对象符合接口/协议的最可靠和可读的方法是什么?
我试图将代码转换为接口(或Objective C术语中的协议),而不是实现 在调用对象上的方法以防止崩溃之前,检查对象是否符合协议是至关重要的 三种方式Objective c 什么';在Objective C中,确保对象符合接口/协议的最可靠和可读的方法是什么?,objective-c,interface,protocols,Objective C,Interface,Protocols,我试图将代码转换为接口(或Objective C术语中的协议),而不是实现 在调用对象上的方法以防止崩溃之前,检查对象是否符合协议是至关重要的 三种方式 在编译器中 运行时 两者 最佳解决方案。。。当然是第一名? 我认为最好的方法是在编译器中: 如果你搞砸了怎么办 删除StopRotocol:/respondsToSelector:样板文件 在运行时,如果您犯了错误,那就太晚了-您所能做的最好的事情就是不执行代码/显示错误 但我看到很多代码都是在运行时执行的。为什么? 这是一个可读性问题吗?
- 如果你搞砸了怎么办
- 删除StopRotocol:/respondsToSelector:样板文件
- 在运行时,如果您犯了错误,那就太晚了-您所能做的最好的事情就是不执行代码/显示错误
id
我的问题
确保对象符合接口/协议的最可靠和可读的方法是什么
代码
@interface ReportController : NSObject {
id generator;
id sender;
id report;
}
@implementation ReportController
-(id)initWithReportGenerator:(id)generator_
reportSender:(id)sender_ {
// Usual init stuff
generator = generator_;
sender = sender_;
return self;
}
-(void)generateAndSend {
if ([generator conformsToProtocol:@protocol(ReportGenerator)] &&
[sender conformsToProtocol:@protocol(ReportSender)]) {
report = [generator generate];
[sender sendReport:report];
} else {
[NSException raise:NSInternalInconsistencyException format:@"Objects didn't respond to protocols..."];
}
}
@end
1。签入编译器
@interface ReportController : NSObject {
id <ReportGenerator> generator;
id <ReportSender> sender;
id report;
}
@implementation ReportController
-(id)initWithReportGenerator:(id <ReportGenerator>)generator_
reportSender:(id <ReportSender>)sender_ {
// Usual init stuff
generator = generator_;
sender = sender_;
return self;
}
-(void)generateAndSend {
report = [generator generate];
[sender sendReport:report];
}
@end
您应该在协议中创建具有@required类型的方法。 所以,无论什么类想要与这个协议签订契约,都必须实现这些方法。
它肯定会确保所需的方法仅在编译时可用。您应该同时使用这两种方法。考虑一下:
@protocol Proto
- (void)someFunction;
@end
@interface C : NSObject
- (void)proto:(id<Proto>)p;
@end
// ...
NSString *s = @"moo";
id i = s;
C *c = [[C alloc] init];
[c proto:s]; // warns
[c proto:i]; // doesn't warn
@协议协议协议
-(空)某些功能;
@结束
@接口C:NSObject
-(void)proto:(id)p;
@结束
// ...
NSString*s=@“moo”;
id i=s;
C*C=[[C alloc]init];
[c proto:s];//警告
[c proto:i];//没有警告
Objective-C和Cocoa过于动态,无法在编译时通常检查这些内容(NSProxy
standins,动态添加方法和协议的类等)。在编译时捕获尽可能多的此类错误是很好的,但仅此一点是不够的。只要您不使用plain
id
作为类型,编译器至少会在您在编译时出错时向您发出警告。因此,您应该对代码示例#1感到满意
当然,有时您可能会被迫使用从不受您控制的子系统获得的id
对象。在这种情况下,您可以将对象强制转换回您认为它具有的类型(例如,id
),但如果您首先执行运行时检查,通常情况下会更好。安全总比后悔好
最后一点注意:如果您的协议有可选部分(用
@optional
关键字声明),那么对于这些部分,您显然只能执行运行时检查。apurv提到的@required
关键字只有在您希望在协议声明中明确说明时才是必需的(默认情况下,协议的部分是必需的),或者如果您混合了可选部分和必需部分。@required
是默认值,它通常不会确保在编译时存在方法。@GeorgFritzsche:您能解释一下“通常不会确保在编译时存在方法”的意思吗?我的印象是,只要您使用显式类型,并且不使用普通的id
,编译器就会检查类是否符合协议。@herzube:一件事是,它只是一个类型检查,在存在像id
这样的非严格转换时,基本上对任何东西都没有帮助。然后,您通常无法确保方法在编译时的存在-实现可能在动态加载的代码(共享库等)、不同的项目/流程(例如分布式对象)中,或者您可能在运行时构建了类。这一点非常好。真不敢相信我之前没看到。所有这些协议检查加上类型检查现在完全有意义了。谢谢还有一个问题-你会如何处理协议不符合-什么都不做?抛出异常?还是返回一个错误?@John:这个问题很难回答,这取决于上下文。