在Objective-C中为类定义私有方法的最佳方法
我刚开始编写Objective-C,有Java背景,想知道编写Objective-C程序的人是如何处理私有方法的 我知道可能有几个惯例和习惯,并将这个问题看作是人们在Objective-C中处理私有方法时使用的最佳技术的集合 请在发布时为您的方法提供一个参数。为什么它好?它有哪些缺点(你知道的)以及你如何处理它们在Objective-C中为类定义私有方法的最佳方法,objective-c,cocoa,code-completion,Objective C,Cocoa,Code Completion,我刚开始编写Objective-C,有Java背景,想知道编写Objective-C程序的人是如何处理私有方法的 我知道可能有几个惯例和习惯,并将这个问题看作是人们在Objective-C中处理私有方法时使用的最佳技术的集合 请在发布时为您的方法提供一个参数。为什么它好?它有哪些缺点(你知道的)以及你如何处理它们 至于我目前的发现 可以使用MyClass.m文件中定义的[例如MyClass(Private)]对私有方法进行分组 这种方法有两个问题: Xcode(和编译器?)不检查是否在相应的@
至于我目前的发现 可以使用MyClass.m文件中定义的[例如MyClass(Private)]对私有方法进行分组 这种方法有两个问题:
第二个问题让我很困扰。我希望看到私有方法在文件末尾附近被实现(和定义);我不知道这是否可能。虽然我不是Objective-C专家,但我个人只是在类的实现中定义了该方法。当然,它必须在(上面)之前定义任何方法都可以调用它,但它肯定只需要最少的工作量。没有真正的“私有方法”“在Objective-C中,如果运行时能够确定使用哪个实现,那么它将完成这项工作。但这并不是说没有方法不是文档化接口的一部分。对于那些方法,我认为分类是好的。我不会像第2点那样将
@interface
放在.m文件的顶部,而是将其放在自己的.h文件中。我遵循的一个约定(在其他地方也看到过,我认为这是苹果的约定,因为Xcode现在自动支持它)是以类和类别命名这样的文件,并用+分隔它们,因此@interface GLObject(PrivateMethods)
可以在GLObject+PrivateMethods.h
中找到。提供头文件的原因是,您可以在单元测试类中导入它:-)
顺便说一下,就在.m文件末尾附近实现/定义方法而言,您可以通过在.m文件底部实现类别来实现类别:
@implementation GLObject(PrivateMethods)
- (void)secretFeature;
@end
@interface MyClass()
- (void)myPrivateMethod;
@end
@implementation MyClass
- (void)myPublicMethod {
// Implementation goes here
}
- (void)myPrivateMethod {
// Implementation goes here
}
@end
或者使用类扩展(您称之为“空类别”),只需最后定义这些方法。Objective-C方法可以在实现中以任何顺序定义和使用,因此没有什么可以阻止您将“private”方法放在文件末尾
即使使用类扩展,我也会经常创建一个单独的头(GLObject+Extension.h
),以便在需要时使用这些方法,模仿“朋友”或“受保护”的可见性
因为这个答案最初是编写的,所以clang编译器已经开始对Objective-C方法进行两次传递。这意味着您可以避免完全声明“私有”方法,无论它们位于调用站点的上方还是下方,编译器都会找到它们。无法回避问题2。这就是C编译器(以及Objective-C编译器)的工作方式。如果使用XCode编辑器,函数弹出窗口应该可以轻松导航文件中的
@接口
和@实现
块。您可以尝试在实现下方或上方定义一个静态函数,该函数将指针指向您的实例。它将能够访问您的任何实例变量
//.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
正如其他人所说,Objective-C中没有私有方法。但是,从Objective-C2.0(意味着Mac OS X Leopard、iPhone OS 2.0和更高版本)开始,您可以创建一个名为Class Extension的空类别(即
@interface MyClass()
)。类扩展的独特之处在于,方法实现必须与公共方法位于相同的@implementation MyClass
中。所以我的课程结构如下:
在.h文件中:
@interface MyClass {
// My Instance Variables
}
- (void)myPublicMethod;
@end
在.m文件中:
@implementation GLObject(PrivateMethods)
- (void)secretFeature;
@end
@interface MyClass()
- (void)myPrivateMethod;
@end
@implementation MyClass
- (void)myPublicMethod {
// Implementation goes here
}
- (void)myPrivateMethod {
// Implementation goes here
}
@end
我认为这种方法的最大优点是,它允许您按功能而不是按顺序(有时是任意的)对方法实现进行分组公共/私有的区别。如果您想避免顶部的
@接口
块,您可以将私有声明放在另一个文件MyClassPrivate.h
中,这并不理想,但不会影响实现
MyClass.h
interface MyClass : NSObject {
@private
BOOL publicIvar_;
BOOL privateIvar_;
}
@property (nonatomic, assign) BOOL publicIvar;
//any other public methods. etc
@end
MyClassPrivate.h
@interface MyClass ()
@property (nonatomic, assign) BOOL privateIvar;
//any other private methods etc.
@end
我的班级
#import "MyClass.h"
#import "MyClassPrivate.h"
@implementation MyClass
@synthesize privateIvar = privateIvar_;
@synthesize publicIvar = publicIvar_;
@end
Objective C中的每个对象都符合NSObject协议,该协议保留了性能选择器:方法。我之前也在寻找一种方法来创建一些不需要公开的“助手或私有”方法。如果您想创建一个没有开销的私有方法,并且不必在头文件中定义它,那么请尝试一下 使用与下面代码类似的签名定义您的方法
-(void)myHelperMethod: (id) sender{
// code here...
}
然后,当您需要引用该方法时,只需将其作为选择器调用
[self performSelector:@selector(myHelperMethod:)];
这行代码将调用您创建的方法,并且不会出现关于未在头文件中定义该方法的恼人警告。缺少私有方法有一个好处。您可以将要隐藏的逻辑移动到单独的类中,并将其用作委托。在这种情况下,您可以将委托对象标记为private,并且从外部看不到它。将逻辑移动到单独的类(可能几个)可以更好地设计项目。使您的类变得更简单,并且将您的方法分组到具有专有名称的类中。您可以使用块吗
@implementation MyClass
id (^createTheObject)() = ^(){ return [[NSObject alloc] init];};
NSInteger (^addEm)(NSInteger, NSInteger) =
^(NSInteger a, NSInteger b)
{
return a + b;
};
//public methods, etc.
- (NSObject) thePublicOne
{
return createTheObject();
}
@end
我知道这是一个老问题,但这是我在寻找时发现的第一个问题
@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
@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
@implementation MyClass
// .. public methods
# pragma mark private
// ...
@end