如何为Objective-C协议提供默认实现?
我想指定一个带有可选例程的Objective-C协议。当例程不是由符合协议的类实现时,我希望使用默认实现来代替它。协议本身是否有一个地方可以定义这个默认实现?如果没有,那么减少这种默认实现的复制和粘贴的最佳实践是什么?Objective-C协议对默认实现没有任何启示。它们纯粹是可以由其他类实现的方法声明的集合。Objective-C中的标准实践是在运行时测试一个对象,查看它是否响应给定的选择器,然后使用-[NSObject respondsToSelector:]对其调用该方法。如果e对象不响应给定的选择器,则不会调用该方法 实现所需结果的一种方法是定义一个方法,该方法封装调用类中所需的默认行为,如果对象未通过测试,则调用该方法 另一种方法是使该方法在协议中成为必需的,并在您可能不希望提供特定实现的任何类的超类中提供默认实现如何为Objective-C协议提供默认实现?,objective-c,protocols,standards-compliance,default-implementation,overhead-minimization,Objective C,Protocols,Standards Compliance,Default Implementation,Overhead Minimization,我想指定一个带有可选例程的Objective-C协议。当例程不是由符合协议的类实现时,我希望使用默认实现来代替它。协议本身是否有一个地方可以定义这个默认实现?如果没有,那么减少这种默认实现的复制和粘贴的最佳实践是什么?Objective-C协议对默认实现没有任何启示。它们纯粹是可以由其他类实现的方法声明的集合。Objective-C中的标准实践是在运行时测试一个对象,查看它是否响应给定的选择器,然后使用-[NSObject respondsToSelector:]对其调用该方法。如果e对象不响应
可能还有其他选择,但一般来说,Objective-C中没有特定的标准实践,除非根据我上面的第一段,如果给定的方法没有被对象实现,可能就不调用它。一个真正有趣的方法是使用运行时。在启动时,在程序执行的早期,执行以下操作:
没有那么多麻烦也可以实现 由于协议不应定义任何实现,因此没有标准的方法来实现这一点 由于Objective-C附带了一个整洁的运行时,如果您真的认为需要这样做,当然可以添加这样的行为(通过继承实现这一点是不可能的) 假设您声明了MyProtocol,那么只需在协议声明下的.h文件中添加一个同名接口:
@interface MyProtocol : NSObject <MyProtocol>
+ (void)addDefaultImplementationForClass:(Class)conformingClass;
@end
那你只要打个电话就行了
[MyProtocol addDefaultImplementationForClass:[self class]];
在符合协议的类的初始值设定项中,将添加所有默认方法。正如Ryan提到的,没有协议的默认实现,在超类中实现的另一个选项是实现“处理程序”可以包含在任何要提供默认实现的类中的类的类型,相应的方法然后调用默认处理程序实现。我最终创建了一个具有该方法默认实现的宏 我已经在协议的头文件中定义了它,然后它在每个实现中只是一行 这样,我就不必在几个地方更改实现,而且它是在编译时完成的,因此不需要运行时魔法。我同意“w.m.”一个非常好的解决方案是将所有默认实现放在一个接口中(与协议同名)。在任何子类的“+initialize”方法中,它可以简单地将任何未实现的方法从默认接口复制到自身中 以下助手函数对我有效
#import <objc/runtime.h>
// Get the type string of a method, such as "v@:".
// Caller must allocate sufficent space. Result is null terminated.
void getMethodTypes(Method method, char*result, int maxResultLen)
{
method_getReturnType(method, result, maxResultLen - 1);
int na = method_getNumberOfArguments(method);
for (int i = 0; i < na; ++i)
{
unsigned long x = strlen(result);
method_getArgumentType(method, i, result + x, maxResultLen - 1 - x);
}
}
// This copies all the instance methods from one class to another
// that are not already defined in the destination class.
void copyMissingMethods(Class fromClass, Class toClass)
{
// This gets the INSTANCE methods only
unsigned int numMethods;
Method* methodList = class_copyMethodList(fromClass, &numMethods);
for (int i = 0; i < numMethods; ++i)
{
Method method = methodList[i];
SEL selector = method_getName(method);
char methodTypes[50];
getMethodTypes(method, methodTypes, sizeof methodTypes);
if (![toClass respondsToSelector:selector])
{
IMP methodImplementation = class_getMethodImplementation(fromClass, selector);
class_addMethod(toClass, selector, methodImplementation, methodTypes);
}
}
free(methodList);
}
#导入
//获取方法的类型字符串,例如“v@:”。
//调用者必须分配足够的空间。结果以null结尾。
void getMethodTypes(方法方法,char*result,int-maxResultLen)
{
方法_getReturnType(方法、结果、maxResultLen-1);
int na=方法\u获取NumberOfArguments(方法);
对于(int i=0;i
然后在类初始值设定项中调用它,例如
@interface Foobar : NSObject<MyProtocol>
@end
@implementation Foobar
+(void)initialize
{
// Copy methods from the default
copyMissingMethods([MyProtocol class], self);
}
@end
@接口Foobar:NSObject
@结束
@实现Foobar
+(无效)初始化
{
//从默认值复制方法
copyMissingMethods([MyProtocol class],self);
}
@结束
Xcode将为您提供有关Foobar缺少方法的警告,但您可以忽略它们
此技术仅复制方法,而不是IVAR。如果这些方法正在访问不存在的数据成员,则可能会出现奇怪的错误。您必须确保数据与代码兼容。这就好像你重新诠释了从Foobar到MyProtocol的角色一样。你怎么敢称之为黑客;)实际上,我已经编写了一个完整的公共域模块来实现这一点。它并不像听起来那么黑客,因为它使用了完全受支持和文档化的功能,并且已经在生产代码中进行了彻底的测试。好吧,我用“引人入胜”来代替“粗俗”。这会让你们都满意吗?也许这不是黑客行为,但这不是标准做法,调试肯定会让人困惑。一个宏?!嘘,嘘。最好的答案是“w.m”。您应该创建一个包含所有默认实现的类。
@interface Foobar : NSObject<MyProtocol>
@end
@implementation Foobar
+(void)initialize
{
// Copy methods from the default
copyMissingMethods([MyProtocol class], self);
}
@end