我尝试将代码添加到接口(或Objective C术语中的协议),而不是实现。
在调用对象之前检查对象是否符合协议以防止崩溃是至关重要的。
三种方式
最佳解决方案......肯定是1号?
我认为最好的方法是在编译器中:
但我看到很多代码都是在运行时做的。为什么?
这是一个可读性问题 - 到处都需要id <Protocol>
吗?
我的问题
确保对象符合接口/协议的最强大和可读的方法是什么?
代码
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
2。在运行时检查
@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
答案 0 :(得分:4)
你应该同时使用两者。考虑例如:
@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
Objective-C和Cocoa太动态了,无法在编译时检查这些内容(NSProxy
替换,类动态添加方法和协议,...)。
很高兴在编译时捕获尽可能多的此类错误,但仅此一点是不够的。
答案 1 :(得分:3)
只要您不使用普通id
作为类型,编译器至少会在编译时出错时向您发出警告。所以你的代码示例#1应该没问题。
当然,有时您可能会被迫使用您从不受您控制的子系统获得的id
对象。在这种情况下,您可以将对象强制转换为它所具有的思想类型(例如id <ReportGenerator>
),但如果先执行运行时检查,通常情况下会更好。最好是安全而不是抱歉...
最后说明:如果您的协议具有可选部分(使用@optional
关键字声明),那么对于这些部分,您显然只能进行运行时检查。 apurv提到的@required
关键字只有在您希望在协议声明中明确时才需要(默认情况下需要协议的部分),或者如果混合使用可选部分和必需部分。
答案 2 :(得分:0)
您应该在协议中使用@required类型创建方法。 因此,无论班级想要与该协议签订合同,都必须实施这些方法。 它肯定会确保所需的方法仅在编译时可用。