Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何为Objective-C协议提供默认实现?_Objective C_Protocols_Standards Compliance_Default Implementation_Overhead Minimization - Fatal编程技术网

如何为Objective-C协议提供默认实现?

如何为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协议对默认实现没有任何启示。它们纯粹是可以由其他类实现的方法声明的集合。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