objective-c 为什么Objective-C 不支持私有方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2158660/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't Objective-C support private methods?
提问by Rob Jones
I've seen a number of strategies for declaring semi-private methods in Objective-C, but there does not seem to be a way to make a truly private method. I accept that. But, why is this so? Every explanation I've essentially says, "you can't do it, but here's a close approximation."
我已经看到了许多在Objective-C 中声明半私有方法的策略,但似乎没有一种方法可以创建真正的私有方法。我接受。但是,为什么会这样呢?我的每一个解释基本上都是在说,“你做不到,但这是一个近似值。”
There are a number of keywords applied to ivars(members) that control their scope, e.g. @private, @public, @protected. Why can't this be done for methods as well? It seems like something the runtime should be able to support. Is there an underlying philosophy I'm missing? Is this deliberate?
有许多应用于ivars(成员)的关键字来控制其范围,例如@private, @public, @protected。为什么不能对方法也这样做?这似乎是运行时应该能够支持的东西。有没有我缺少的基本哲学?这是故意的吗?
采纳答案by bbum
The answer is... well... simple. Simplicity and consistency, in fact.
答案是……嗯……很简单。事实上,简单性和一致性。
Objective-C is purely dynamic at the moment of method dispatch. In particular, every method dispatch goes through the exact same dynamic method resolution point as every other method dispatch. At runtime, every method implementation has the exact same exposure and all of the APIs provided by the Objective-C runtime that work with methods and selectors work equally the same across all methods.
Objective-C 在方法分派时是完全动态的。特别是,每个方法分派都经过与其他所有方法分派完全相同的动态方法解析点。在运行时,每个方法实现都具有完全相同的暴露,并且由 Objective-C 运行时提供的所有 API 与方法和选择器一起工作,在所有方法中都同样工作。
As many have answered (both here and in other questions), compile-time private methods are supported; if a class doesn't declare a method in its publicly available interface, then that method might as well not exist as far as your code is concerned. In other words, you can achieve all of the various combinations of visibility desired at compilation time by organizing your project appropriately.
正如许多人所回答的(这里和其他问题),编译时私有方法是受支持的;如果一个类没有在其公开可用的接口中声明一个方法,那么就您的代码而言,该方法也可能不存在。换句话说,您可以通过适当地组织项目来实现编译时所需的所有各种可见性组合。
There is little benefit to duplicating the same functionality into the runtime. It would add a tremendous amount of complexity and overhead. And even with all of that complexity, it still wouldn't prevent all but the most casual developer from executing your supposedly "private" methods.
将相同的功能复制到运行时几乎没有什么好处。它会增加大量的复杂性和开销。即使有所有这些复杂性,它仍然不能阻止除了最随意的开发人员之外的所有人执行您所谓的“私有”方法。
EDIT: One of the assumptions I've noticed is that private messages would have to go through the runtime resulting in a potentially large overhead. Is this absolutely true?
Yes, it is. There's no reason to suppose that the implementor of a class would not want to use all of the Objective-C feature set in the implementation, and that means that dynamic dispatch must happen. However, there is no particular reason why private methods couldn't be dispatched by a special variant of
objc_msgSend(), since the compiler would know that they were private; i.e. this could be achieved by adding a private-only method table to theClassstructure.There would be no way for a private method to short-circuit this check or skip the runtime?
It couldn't skip the runtime, but the runtime wouldn'tnecessarily have to do any checking for private methods.
That said, there's no reason that a third-party couldn't deliberately call
objc_msgSendPrivate()on an object, outside of the implementation of that object, and some things (KVO, for example) would have to do that. In effect, it would just be a convention and little better in practice than prefixing private methods' selectors or not mentioning them in the interface header.
编辑:我注意到的假设之一是私人消息必须经过运行时,从而导致潜在的大量开销。这绝对是真的吗?
是的。没有理由假设一个类的实现者不想在实现中使用所有的 Objective-C 特性集,这意味着必须发生动态调度。 但是,私有方法不能由 的特殊变体调度并没有特别的原因
objc_msgSend(),因为编译器会知道它们是私有的;即这可以通过向Class结构中添加一个私有方法表来实现。私有方法无法短路此检查或跳过运行时吗?
它不能跳过运行,但运行时也不会一定要做到为私有方法的任何检查。
也就是说,第三方没有理由不能
objc_msgSendPrivate()在该对象的实现之外故意调用一个对象,并且某些事情(例如 KVO)必须这样做。实际上,这只是一个约定,在实践中比在私有方法的选择器前面加上前缀或不在接口头中提及它们更好。
To do so, though, would undermine the pure dynamic nature of the language. No longer would every method dispatch go through an identical dispatch mechanism. Instead, you would be left in a situation where most methods behave one way and a small handful are just different.
但是,这样做会破坏语言的纯动态特性。不再每个方法分派都经过相同的分派机制。取而代之的是,您将处于大多数方法以一种方式运行而少数方法不同的情况。
This extends beyond the runtime as there are many mechanisms in Cocoa built on top of the consistent dynamism of Objective-C. For example, both Key Value Coding and Key Value Observation would either have to be very heavily modified to support private methods — most likely by creating an exploitable loophole — or private methods would be incompatible.
这超出了运行时的范围,因为 Cocoa 中有许多建立在 Objective-C 一致动态之上的机制。例如,Key Value Coding 和 Key Value Observation 要么必须进行大量修改以支持私有方法——很可能是通过创建一个可利用的漏洞——或者私有方法将不兼容。
回答by dreamlax
The runtime could support it but the cost would be enormous. Every selector that is sent would need to be checked for whether it is private or public for that class, or each class would need to manage two separate dispatch tables. This isn't the same for instance variables because this level of protection is done at compile time.
运行时可以支持它,但成本将是巨大的。发送的每个选择器都需要检查该类是私有的还是公共的,或者每个类都需要管理两个单独的调度表。这与实例变量不同,因为这种级别的保护是在编译时完成的。
Also, the runtime would need to verify that the sender of a private message is of the same class as the receiver. You could also bypass private methods; if the class used instanceMethodForSelector:, it could give the returned IMPto any other class for them to invoke the private method directly.
此外,运行时需要验证私人消息的发送者是否与接收者属于同一类。你也可以绕过私有方法;如果使用了类instanceMethodForSelector:,它可以将返回的返回IMP给任何其他类,以便它们直接调用私有方法。
Private methods could not bypass the message dispatch. Consider the following scenario:
私有方法无法绕过消息调度。考虑以下场景:
A class
AllPublichas a public instance methoddoSomethingAnother class
HasPrivatehas a private instance method also calleddoSomethingYou create an array containing any number of instances of both
AllPublicandHasPrivateYou have the following loop:
for (id anObject in myArray) [anObject doSomething];If you ran that loop from within
AllPublic, the runtime would have to stop you sendingdoSomethingon theHasPrivateinstances, however this loop would be usable if it was inside theHasPrivateclass.
一个类
AllPublic有一个公共实例方法doSomething另一个类
HasPrivate有一个私有实例方法,也称为doSomething您创建一个数组,其中包含任意数量的
AllPublic和HasPrivate您有以下循环:
for (id anObject in myArray) [anObject doSomething];如果你从内跑了循环
AllPublic,运行时间将不得不停止在发送doSomething的HasPrivate情况,但是这循环将是可用的,如果它是内部HasPrivate类。
回答by mipadi
The answers posted thus far do a good job of answering the question from a philosophical perspective, so I'm going to posit a more pragmatic reason: what would be gained by changing the semantics of the language? It's simple enough to effectively "hide" private methods. By way of example, imagine you have a class declared in a header file, like so:
迄今为止发布的答案从哲学的角度很好地回答了这个问题,所以我将提出一个更实用的理由:改变语言的语义会得到什么?有效地“隐藏”私有方法很简单。举例来说,假设您在头文件中声明了一个类,如下所示:
@interface MyObject : NSObject {}
- (void) doSomething;
@end
If you have a need for "private" methods, you can also put this in the implementation file:
如果你需要“私有”方法,你也可以把它放在实现文件中:
@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
Sure, it's not quitethe same as C++/Java private methods, but it's effectively close enough, so why alter the semantics of the language, as well as the compiler, runtime, etc., to add a feature that's already emulated in an acceptable way? As noted in other answers, the message-passing semantics -- and their reliance on runtime reflection -- would make handling "private" messages non-trivial.
当然,这不是很一样的C ++ / Java的私有方法,但它有效的足够接近,那么为什么改变语言的语义,以及编译器,运行时间等,以补充一个已经在可接受模拟功能道路?正如其他答案中所指出的,消息传递语义——以及它们对运行时反射的依赖——将使处理“私有”消息变得非常重要。
回答by Cromulent
The easiest solution is just to declare some static C functions in your Objective-C classes. These only have file scope as per the C rules for the static keyword and because of that they can only be used by methods in that class.
最简单的解决方案是在您的 Objective-C 类中声明一些静态 C 函数。根据 static 关键字的 C 规则,这些仅具有文件范围,因此它们只能由该类中的方法使用。
No fuss at all.
一点都不大惊小怪。
回答by Huperniketes
Yes, it can be done without affecting the runtime by utilizing a technique already employed by the compiler(s) for handling C++: name-mangling.
是的,它可以在不影响运行时的情况下通过利用编译器已经用于处理 C++ 的技术来完成:名称修改。
It hasn't been done because it hasn't been established that it would solve some considerable difficulty in the coding problem space that other techniques (e.g., prefixing or underscoring) are able to circumvent sufficiently. IOW, you need more pain to overcome ingrained habits.
还没有完成,因为还没有确定它会解决编码问题空间中的一些相当大的困难,而其他技术(例如,前缀或下划线)能够充分规避。IOW,你需要更多的痛苦来克服根深蒂固的习惯。
You could contribute patches to clang or gcc that add private methods to the syntax and generated mangled names that it alone recognized during compilation (and promptly forgot). Then others in the Objective-C community would be able to determine whether it was actually worthwhile or not. It's likely to be faster that way than trying to convince the developers.
您可以向 clang 或 gcc 提供补丁,这些补丁将私有方法添加到语法中,并生成在编译期间单独识别(并立即忘记)的损坏名称。然后,Objective-C 社区中的其他人将能够确定它是否真的值得。这种方式可能比试图说服开发人员更快。
回答by Chuck
Essentially, it has to do with Objective-C's message-passing form of method calls. Any message can be sent to any object, and the object chooses how to respond to the message. Normally it will respond by executing the method named after the message, but it could respond in a number of other ways too. This doesn't make private methods completely impossible — Ruby does it with a similar message-passing system — but it does make them somewhat awkward.
本质上,它与Objective-C 的方法调用的消息传递形式有关。任何消息都可以发送给任何对象,对象选择如何响应消息。通常它会通过执行以消息命名的方法来响应,但它也可以以多种其他方式响应。这并不会使私有方法完全不可能——Ruby 使用类似的消息传递系统来实现——但它确实让它们有些尴尬。
Even Ruby's implementation of private methods is a bit confusing to people because of the strangeness (you can send the object any message you like, except for the ones on this list!). Essentially, Ruby makes it work by forbidding private methods to be called with an explicit receiver. In Objective-C it would require even more work since Objective-C doesn't have that option.
甚至 Ruby 对私有方法的实现也让人们有点困惑,因为它很奇怪(你可以向对象发送任何你喜欢的消息,除了这个列表中的消息!)。本质上,Ruby 通过禁止使用显式接收器调用私有方法来使其工作。在 Objective-C 中,它需要更多的工作,因为 Objective-C 没有那个选项。
回答by pokstad
It's an issue with the runtime environment of Objective-C. While C/C++compiles down into unreadable machine code, Objective-C still maintains some human-readable attributes like method names as strings. This gives Objective-C the ability to perform reflectivefeatures.
这是Objective-C 的运行时环境的问题。虽然 C/C++编译成不可读的机器代码,但Objective-C 仍然维护一些人类可读的属性,如方法名称作为字符串。这使 Objective-C 能够执行反射功能。
EDIT:Being a reflective language without strict private methods makes Objective-C more "pythonic" in that you trust other people that use your code rather than restrict what methods they can call. Using naming conventions like double underscores is meant to hide your code from a casual client coder, but won't stop coders needing to do more serious work.
编辑:作为没有严格私有方法的反射语言使 Objective-C 更加“pythonic”,因为您信任使用您的代码的其他人,而不是限制他们可以调用的方法。使用像双下划线这样的命名约定是为了向临时的客户端编码员隐藏您的代码,但不会阻止编码员需要做更认真的工作。
回答by AlBlue
There are two answers depending on the interpretation of the question.
根据对问题的解释,有两种答案。
The first is by hiding the method implementation from the interface. This is used, typically with a category with no name (e.g. @interface Foo()). This permits the object to send those messages but not others - though one might still override accidentally (or otherwise).
第一种是通过对接口隐藏方法实现。这通常用于没有名称的类别(例如@interface Foo())。这允许对象发送这些消息而不是其他消息——尽管仍然可能会意外地(或以其他方式)覆盖。
The second answer, on the assumption that this is about performance and inlining, is made possible but as a local C function instead. If you wanted a ‘private foo(NSString *arg)‘ method, you would do void MyClass_foo(MyClass *self, NSString *arg)and call it as a C function like MyClass_foo(self,arg). The syntax is different, but it acts with the sane kind of performance characteristics of C++'s private methods.
第二个答案,假设这是关于性能和内联,是可能的,但作为一个本地 C 函数。如果您想要一个“私有 foo( NSString *arg)”方法,您可以将void MyClass_foo(MyClass *self, NSString *arg)其作为 C 函数调用,例如MyClass_foo(self,arg). 语法不同,但它具有 C++ 私有方法的正常性能特征。
Although this answers the question, I should point out that the no-name category is by far the more common Objective-C way of doing this.
虽然这回答了问题,但我应该指出,无名类别是迄今为止更常见的 Objective-C 方式。
回答by gnasher729
Objective-C doesn't support private methods because it doesn't need them.
Objective-C 不支持私有方法,因为它不需要它们。
In C++, every method must be visible in the declaration of the class. You can't have methods that someone including the header file cannot see. So if you want methods that code outside your implementation shouldn't use, you have no choice, the compiler must give you some tool so you can tell it that the method must not be used, that is the "private" keyword.
在 C++ 中,每个方法都必须在类的声明中可见。您不能拥有包括头文件在内的人看不到的方法。因此,如果您想要不应该使用实现之外的代码的方法,您别无选择,编译器必须为您提供一些工具,以便您可以告诉它不得使用该方法,即“私有”关键字。
In Objective-C, you can have methods that are not in the header file. So you achieve the same purpose very easily by not adding the method to the header file. There's no need for private methods. Objective-C also has the advantage that you don't need to recompile every user of a class because you changed private methods.
在 Objective-C 中,您可以拥有不在头文件中的方法。因此,通过不将方法添加到头文件中,您可以非常轻松地实现相同的目的。不需要私有方法。Objective-C 的另一个优点是您不需要重新编译类的每个用户,因为您更改了私有方法。
For instance variables, that you used to have to declare in the header file (not anymore), @private, @public and @protected are available.
例如,您过去必须在头文件中声明(不再)的实例变量,@private、@public 和 @protected 可用。
回答by Stephan Eggermont
A missing answer here is: because private methods are a bad idea from an evolvability point of view. It might seem a good idea to make a method private when writing it, but it is a form of early binding. The context might change, and a later user might want to use a different implementation. A bit provocative: "Agile developers don't use private methods"
这里缺少的答案是:因为从可进化性的角度来看,私有方法是一个坏主意。在编写方法时将其设为私有似乎是个好主意,但它是一种早期绑定形式。上下文可能会改变,后来的用户可能想要使用不同的实现。有点挑衅:“敏捷开发人员不使用私有方法”
In a way, just like Smalltalk, Objective-C is for grown-up programmers. We value knowing what the original developer assumed the interface should be, and take the responsibility to deal with the consequences if we need to change implementation. So yes, it is philosophy, not implementation.
在某种程度上,就像 Smalltalk 一样,Objective-C 是为成年程序员设计的。我们很重视知道最初的开发人员假设接口应该是什么,如果我们需要改变实现,我们有责任处理后果。所以是的,这是哲学,而不是实施。

