在NSObject上使用类别提供默认协议实现有什么问题?

时间:2013-10-12 00:55:17

标签: ios objective-c protocols objective-c-runtime objective-c-category

我一直在寻找一种使用可选协议方法并拥有干净代码的方法。换句话说:
1:我的代码中没有respondsToSelector:来电 2.应该适用于任何方法签名,因此NSObject上的类别方法进行检查并调用performSelector:(NSInvocation与ARC合作有问题)
3:这个solution,IMO,假装是普遍的,但有1的所有缺点

我最终提出了这个想法:

@protocol MyProtocol <NSObject>
@optional
-(void)optionalMethod;
@end

@interface ClassA : NSObject <MyProtocol>
@end

@implementation ClassA

-(void)optionalMethod{
     NSLog(@"ClassA implements optionalMethod");
}

@end

@interface ClassB : NSObject <MyProtocol>
@end

@implementation ClassB
//classB does not implement optionalMethod
@end

@interface NSObject (DefaultMyProtocolImplementation)
-(void)optionalMethod;
@end

@implementation NSObject (DefaultMyProtocolImplementation)
-(void)optionalMethod{
     NSLog(@"%@ does not implement optionalMethod", NSStringFromClass([self class]));
}
@end

似乎有效,即:

...
ClassA *objA = [[ClassA alloc] init];
ClassB *objB = [[ClassB alloc] init];

[objA optionalMethod]; //prints "ClassA implements optionalMethod"
[objB optionalMethod]; //prints "ClassB does not implement optionalMethod"

虽然网上很多地方都在讨论这个问题,但我没有偶然发现这个解决方案,这让我觉得它有些问题 - 它会失败或者无法预测的一些重大案例。

我应该这样做,还是我的担忧有效?

1 个答案:

答案 0 :(得分:7)

添加到现有系统类的方法应该以某种方式加上前缀。即exec_myMethodexec_doSomethingToThis:。所以,你的解决方案违反了这一点。

除此之外,它还意味着一个类不能选择退出任何默认的@optional方法的行为(基本上没什么,因为你的默认实现应该是一个无操作)。

所以,不,总的来说,除了违反应该添加前缀规则以提供默认实现以通过类别向现有类添加方法之外,没有什么可怕的错误。但这不是一个严格的规则。

另一个缺点是您正在污染方法命名空间。这在开发过程中将是一个缺点,因为Xcode将编写完成所有方法的代码,通过简单地不暴露声明(不需要公开)就可以轻松避免。在运行时,这意味着respondsToSelector:对这些方法没用,但这有点像设计。

仍然......它闻到了这个旧计时器的代码嗅觉中心。