当前位置:  开发笔记 > 编程语言 > 正文

为什么Objective-C不支持私有方法?

如何解决《为什么Objective-C不支持私有方法?》经验,为你挑选了5个好方法。

我已经看到了一些在Objective-C中声明半私有方法的策略,但似乎没有办法制作一个真正的私有方法.我接受.但是,为什么会这样呢?我基本上所说的每一个解释,"你不能这样做,但这里有一个近似的近似."

有许多适用于关键字的ivars(部件)控制它们的范围,例如@private,@public,@protected.为什么不能这样做呢?它似乎是运行时应该能够支持的东西.我缺少一种潜在的哲学吗?这是故意的吗?



1> bbum..:

答案是......好吧......简单.事实上,简单性和一致性.

Objective-C在方法调度时是纯动态的.特别是,每个方法调度都经历与每个其他方法调度完全相同的动态方法解析点.在运行时,每个方法实现都具有完全相同的暴露,并且与方法和选择器一起使用的Objective-C运行时提供的所有API在所有方法中的工作方式相同.

正如许多人已经回答的那样(这里和其他问题),支持编译时私有方法; 如果一个类没有在其公共可用接口中声明一个方法,那么就您的代码而言,该方法可能也不存在.换句话说,通过适当地组织项目,您可以在编译时实现所需的所有可见性组合.

将相同的功能复制到运行时几乎没有什么好处.这会增加大量的复杂性和开销.即使具有所有这些复杂性,它仍然不会阻止除了最随意的开发人员以外的所有人执行您所谓的"私有"方法.

编辑:我注意到的一个假设是私有消息必须通过运行时导致潜在的大开销.这绝对是真的吗?

是的.没有理由认为类的实现者不希望在实现中使用所有Objective-C功能集,这意味着必须发生动态调度. 但是,objc_msgSend()由于编译器会知道私有方法是私有的,因此没有特殊原因可以通过特殊变体来调度私有方法.即,这可以通过向Class结构添加仅私有方法表来实现.

私有方法无法使此检查短路或跳过运行时?

它不能跳过运行,但运行时也不会一定要做到为私有方法的任何检查.

也就是说,没有理由第三方不能故意调用objc_msgSendPrivate()一个对象,除了该对象的实现之外,有些东西(例如KVO)必须这样做.实际上,它只是一个约定,在实践中比在私有方法的选择器前缀或在接口头中不提及它们更好.

但是,这样做会破坏语言的纯粹动态性质.每个方法调度都不再需要通过相同的调度机制.相反,你将处于这样一种情况,即大多数方法都表现为单向,而少数方法只是不同.

这延伸到运行时之外,因为Cocoa中有许多机制是建立在Objective-C的一致动态之上的.例如,密钥值编码和密钥值观察都必须经过大量修改以支持私有方法 - 最有可能通过创建可利用的漏洞 - 或私有方法是不兼容的.


+1 Objective-C是(在某些方面)一种"大男孩"语言,其中程序员应该表现出一定程度的纪律,而不是每次都被编译器/运行时打包.我发现它令人耳目一新 对我来说,在编译/链接期间限制方法可见性是充分和可取的.
更多python是"obj-c-ic":).Guido非常积极地在NeXT系统上维护Python,包括创建第一版PyObjC.因此,ObjC确实影响了python**.
谢谢.Python,Java和Objective-C都有运行时对象模型,这些模型与[SmallTalk]类似.Java直接源自Objective-C.Python运行并行课程的灵感不止一个,但Guido肯定会密切研究NeX​​TSTEP.
+1为有关生命的仁慈独裁者和他与神话般的NeXT系统的交叉的有趣历史故事.

2> dreamlax..:

运行时可以支持它,但成本会很高.发送的每个选择器都需要检查该类是私有的还是公共的,或者每个类需要管理两个单独的分派表.这与实例变量不同,因为这种保护级别是在编译时完成的.

此外,运行时需要验证私有消息的发送者是否与接收者属于同一类.你也可以绕过私人方法; 如果使用了类instanceMethodForSelector:,它可以将返回IMP给任何其他类,以便它们直接调用私有方法.

私有方法无法绕过消息调度.请考虑以下情形:

    AllPublic具有公共实例方法doSomething

    另一个类HasPrivate也有一个私有实例方法doSomething

    您创建一个包含两个AllPublic和的任意数量实例的数组HasPrivate

    你有以下循环:

    for (id anObject in myArray)
        [anObject doSomething];
    

    如果你从内跑了循环AllPublic,运行时间将不得不停止在发送doSomethingHasPrivate情况,但是这循环将是可用的,如果它是内部HasPrivate类.


私人方法会给你带来什么,真的吗?毕竟,Objective-C是一种基于C语言.因此,如果有人在您的流程中运行了代码,那么无论任何API可能是私有的还是混淆的,他们都可以轻松地执行您的流程.

3> mipadi..:

到目前为止发布的答案很好地从哲学的角度回答了这个问题,所以我将提出一个更实用的理由:通过改变语言的语义会得到什么?它足够简单,可以有效地"隐藏"私有方法.举例来说,假设您在头文件中声明了一个类,如下所示:

@interface MyObject : NSObject {}
- (void) doSomething;
@end

如果您需要"私有"方法,还可以将其放在实现文件中:

@interface MyObject (Private)
- (void) doSomeHelperThing;
@end

@implementation MyObject

- (void) doSomething
{
    // Do some stuff
    [self doSomeHelperThing];
    // Do some other stuff;
}

- (void) doSomeHelperThing
{
    // Do some helper stuff
}

@end

当然,这不是一样的C++/Java的私有方法,但它足以有效地接近,所以为什么改变语言,以及编译器,运行时间等的语义,添加一个已经在可接受模拟功能办法?正如其他答案所述,消息传递语义 - 以及它们对运行时反射的依赖 - 将使处理"私有"消息变得非常重要.


此外,在方法之后输入您的SSN,以便其他程序员知道谁编写了它.= D命名空间,需要它们!
这对我来说就像是黑客攻击.
如果您担心被定义的方法被覆盖,那么您还没有正确地接受Objective-C鼓励的内在级别的详细程度......

4> Cromulent..:

最简单的解决方案是在Objective-C类中声明一些静态C函数.这些只有静态关键字的C规则的文件范围,因此它们只能由该类中的方法使用.

不用大惊小怪.



5> Huperniketes..:

是的,它可以通过利用编译器已经采用的技术来处理C++而不影响运行时完成:名称修改.

尚未完成,因为尚未确定它将解决编码问题空间中的一些相当大的困难,其他技术(例如,前缀或下划线)能够充分规避.IOW,你需要更多的痛苦来克服根深蒂固的习惯.

您可以为clang或gcc提供补丁,为语法添加私有方法,并生成在编译过程中单独识别的错误名称(并立即忘记).然后,Objective-C社区中的其他人将能够确定它是否真的值得.它可能比试图说服开发者更快.


编译时间名称修改比人们假设的要困难得多,因为你必须破坏所有方法选择器,包括可能出现在XIB文件中的那些以及可能传递给NSSelectorFromString()以及KeyValueCoding和朋友之类的东西......
推荐阅读
pan2502851807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有