我刚开始编写Objective-C,有Java背景,不知道人们写Objective-C程序是如何处理私有方法的。
我知道可能会有一些约定和习惯,把这个问题看作是人们在Objective-C中处理私有方法时使用的最佳技术的集合。
请包括一个论点,你的方法张贴时。为什么它是好的?你知道它有哪些缺点,你是如何处理它们的?
至于我目前的发现。
可以使用MyClass中定义的类别[例如MyClass (Private)]。M文件对私有方法进行分组。
这种方法有两个问题:
Xcode(和编译器?)不会检查你是否在相应的@implementation块中定义了私有类别中的所有方法
你必须把@interface放在MyClass的开头声明你的私有类别。m文件,否则Xcode抱怨一个消息像“self可能不响应消息“privateFoo”。
第一个问题可以用空类别来解决[例如MyClass()]。
第二个问题让我很困扰。我希望在文件末尾看到私有方法的实现(和定义);我不知道这是否可能。
您可以尝试在实现的下面或上面定义一个静态函数,该函数接受指向实例的指针。它将能够访问您的任何实例变量。
//.h file
@interface MyClass : Object
{
int test;
}
- (void) someMethod: anArg;
@end
//.m file
@implementation MyClass
static void somePrivateMethod (MyClass *myClass, id anArg)
{
fprintf (stderr, "MyClass (%d) was passed %p", myClass->test, anArg);
}
- (void) someMethod: (id) anArg
{
somePrivateMethod (self, anArg);
}
@end
There isn't really a "private method" in Objective-C, if the runtime can work out which implementation to use it will do it. But that's not to say that there aren't methods which aren't part of the documented interface. For those methods I think that a category is fine. Rather than putting the @interface at the top of the .m file like your point 2, I'd put it into its own .h file. A convention I follow (and have seen elsewhere, I think it's an Apple convention as Xcode now gives automatic support for it) is to name such a file after its class and category with a + separating them, so @interface GLObject (PrivateMethods) can be found in GLObject+PrivateMethods.h. The reason for providing the header file is so that you can import it in your unit test classes :-).
顺便说一下,至于在.m文件末尾实现/定义方法,你可以通过在.m文件底部实现category来做到这一点:
@implementation GLObject(PrivateMethods)
- (void)secretFeature;
@end
或者使用类扩展(你称之为“空类别”的东西),最后定义这些方法。Objective-C方法可以在实现中以任何顺序定义和使用,因此没有什么可以阻止您将“私有”方法放在文件的末尾。
即使使用类扩展,我也经常会创建一个单独的头文件(GLObject+Extension.h),以便在需要时使用这些方法,模仿“好友”或“受保护”可见性。
因为这个答案是最初编写的,clang编译器已经开始为Objective-C方法进行两次传递。这意味着你可以完全避免声明你的“私有”方法,无论它们是在调用站点的上面还是下面,它们都会被编译器找到。
Objective C中的每个对象都遵循NSObject协议,该协议保留了performSelector:方法。我以前也在寻找一种方法来创建一些“辅助或私有”方法,我不需要在公共级别上公开这些方法。如果你想创建一个没有开销的私有方法,并且不需要在头文件中定义它,那么就试试这个…
用与下面代码相似的签名定义your方法…
-(void)myHelperMethod: (id) sender{
// code here...
}
然后,当你需要引用该方法时,只需将其作为选择器调用…
[self performSelector:@selector(myHelperMethod:)];
这行代码将调用您创建的方法,并且不会出现关于头文件中没有定义该方法的恼人警告。
在@implementation块中定义私有方法对于大多数目的来说是理想的。不管声明顺序如何,Clang将在@implementation中看到这些。不需要在类延续(又名类扩展)或命名类别中声明它们。
在某些情况下,你需要在类延续中声明方法(例如,如果在类延续和@implementation之间使用选择器)。
静态函数对于特别敏感或速度关键的私有方法非常有用。
命名前缀的约定可以帮助您避免意外重写私有方法(我发现类名作为前缀是安全的)。
命名类别(例如@interface MONObject (PrivateStuff))不是一个特别好的主意,因为在加载时可能会发生命名冲突。它们实际上只对朋友或受保护的方法有用(这很少是一个好的选择)。为了确保你被警告不完整的类别实现,你应该实际实现它:
@implementation MONObject (PrivateStuff)
...HERE...
@end
这里有一个带注释的小抄:
MONObject.h
@interface MONObject : NSObject
// public declaration required for clients' visibility/use.
@property (nonatomic, assign, readwrite) bool publicBool;
// public declaration required for clients' visibility/use.
- (void)publicMethod;
@end
MONObject.m
@interface MONObject ()
@property (nonatomic, assign, readwrite) bool privateBool;
// you can use a convention where the class name prefix is reserved
// for private methods this can reduce accidental overriding:
- (void)MONObject_privateMethod;
@end
// The potentially good thing about functions is that they are truly
// inaccessible; They may not be overridden, accidentally used,
// looked up via the objc runtime, and will often be eliminated from
// backtraces. Unlike methods, they can also be inlined. If unused
// (e.g. diagnostic omitted in release) or every use is inlined,
// they may be removed from the binary:
static void PrivateMethod(MONObject * pObject) {
pObject.privateBool = true;
}
@implementation MONObject
{
bool anIvar;
}
static void AnotherPrivateMethod(MONObject * pObject) {
if (0 == pObject) {
assert(0 && "invalid parameter");
return;
}
// if declared in the @implementation scope, you *could* access the
// private ivars directly (although you should rarely do this):
pObject->anIvar = true;
}
- (void)publicMethod
{
// declared below -- but clang can see its declaration in this
// translation:
[self privateMethod];
}
// no declaration required.
- (void)privateMethod
{
}
- (void)MONObject_privateMethod
{
}
@end
另一种可能不太明显的方法是:c++类型既可以非常快,又可以提供更高程度的控制,同时最大限度地减少导出和加载objc方法的数量。
其他人已经说过,Objective-C中没有私有方法。然而,从Objective-C 2.0(意味着Mac OS X Leopard, iPhone OS 2.0和更高版本)开始,你可以创建一个名为类扩展的空名称(即@interface MyClass())的类别。类扩展的独特之处在于方法实现必须与公共方法放在同一个@implementation MyClass中。所以我的课程结构是这样的:
在.h文件中:
@interface MyClass {
// My Instance Variables
}
- (void)myPublicMethod;
@end
在.m文件中:
@interface MyClass()
- (void)myPrivateMethod;
@end
@implementation MyClass
- (void)myPublicMethod {
// Implementation goes here
}
- (void)myPrivateMethod {
// Implementation goes here
}
@end
我认为这种方法最大的优点是,它允许您根据功能对方法实现进行分组,而不是根据(有时是任意的)公共/私有区分进行分组。