什么是确保对象符合Objective C中的接口/协议的最强大和可读的方法?

时间:2012-02-18 16:30:56

标签: objective-c interface protocols

我尝试将代码添加到接口(或Objective C术语中的协议),而不是实现。

在调用对象之前检查对象是否符合协议以防止崩溃是至关重要的。

三种方式

  1. 在编译器
  2. 在运行时
  3. 两个
  4. 最佳解决方案......肯定是1号?

    我认为最好的方法是在编译器中:

    • 警告呀,如果你搞砸了
    • 消除conformsToProtocol:/ respondsToSelector:样板
    • 在运行时,如果你犯了一个错误就太晚了 - 你能做的最好就是不执行代码/显示错误

    但我看到很多代码都是在运行时做的。为什么?

    这是一个可读性问题 - 到处都需要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
    

3 个答案:

答案 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类型创建方法。 因此,无论班级想要与该协议签订合同,都必须实施这些方法。 它肯定会确保所需的方法仅在编译时可用。