Best way to define private methods for a class in Objective-C
我刚开始编程ObjuleC,在Java中有一个背景,不知道人们编写ObjuleC程序是如何处理私有方法的。
我理解可能有一些惯例和习惯,并把这个问题当作人们在客观C中处理私有方法时使用的最佳技术的集合。
请在发布方法时包含一个参数。为什么很好?它有哪些缺点(你知道的)以及你如何处理它们?
至于到目前为止我的发现。
可以使用myclass.m文件中定义的类别[例如myclass(private)]对私有方法进行分组。
这种方法有两个问题:
第一个问题可以用空类别解决[例如myclass()]。第二个很困扰我。我希望看到在文件的末尾实现(和定义)私有方法;我不知道这是否可行。
正如其他人已经说过的,在Objective-C中没有私有方法。但是,从Objective-C 2.0(即Mac OS X Leopard、iPhone OS 2.0及更高版本)开始,您可以创建一个名为类扩展的空名称(即
在.h文件中:
1 2 3 4 5 6 7 | @interface MyClass { // My Instance Variables } - (void)myPublicMethod; @end |
在.m文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @interface MyClass() - (void)myPrivateMethod; @end @implementation MyClass - (void)myPublicMethod { // Implementation goes here } - (void)myPrivateMethod { // Implementation goes here } @end |
我认为这种方法的最大优点是它允许您按功能对方法实现进行分组,而不是(有时是任意的)公共/私有区别。
在Objective-C中没有真正的"私有方法",如果运行时能够计算出要使用哪个实现,那么它就可以做到这一点。但这并不是说没有不属于文档化接口的方法。对于这些方法,我认为分类是可以的。我不想把
顺便说一下,对于.m文件末尾附近的实现/定义方法,您可以通过实现.m文件底部的类别来对类别执行此操作:
1 2 3 | @implementation GLObject(PrivateMethods) - (void)secretFeature; @end |
或者使用类扩展(您称之为"空类别"),只需最后定义这些方法。Objective-C方法可以在实现中以任何顺序定义和使用,因此没有什么可以阻止您将"私有"方法放在文件的末尾。
即使有了类扩展,我也常常会创建一个单独的头(
因为这个答案最初是写的,所以clang编译器已经开始为objective-c方法做两次传递。这意味着您可以避免完全声明您的"私有"方法,无论它们在调用站点的上方还是下方,编译器都会找到它们。
虽然我不是Objective-C专家,但我个人只是在我的类的实现中定义方法。当然,它必须在调用它的任何方法之前(在上面)进行定义,但它确实需要最少的工作量。
在
在某些情况下,您需要在类继续符中声明方法(例如,如果在类继续符和
命名前缀的约定可以帮助您避免意外地重写私有方法(我发现类名是安全的前缀)。
命名类别(例如
1 2 3 | @implementation MONObject (PrivateStuff) ...HERE... @end |
下面是一个带注释的小纸条:
单目标
1 2 3 4 5 6 7 8 9 | @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 |
M对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | @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方法的数量。
您可以尝试在实现的下面或上面定义一个静态函数,该函数接受一个指向实例的指针。它将能够访问您的任何实例变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | //.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 |
你可以用积木吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @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 |
我知道这是一个古老的问题,但这是我在寻找这个问题的答案时发现的第一个问题。我没有看到其他地方讨论过这个解决方案,所以请告诉我做这个是否有什么愚蠢的地方。
目标C中的每个对象都符合nsObject协议,该协议保留了performSelector:方法。我以前也在寻找一种方法来创建一些不需要在公共级别公开的"助手或私有"方法。如果您想创建一个没有开销的私有方法,并且不需要在头文件中定义它,那么就给它一个例子……
用与下面代码类似的签名定义您的方法…
1 2 3 | -(void)myHelperMethod: (id) sender{ // code here... } |
然后当需要引用该方法时,只需将其作为选择器调用…
1 | [self performSelector:@selector(myHelperMethod:)]; |
这一行代码将调用您创建的方法,并且不会对没有在头文件中定义该方法发出恼人的警告。
还有一件事我在这里没有看到提到——xcode支持名为"private"的.h文件。假设您有一个类myclass—您有myclass.m和myclass.h,现在您也可以有myclass_private.h。xcode将识别这一点,并将其包含在助理编辑器的"副本"列表中。
1 2 3 | //MyClass.m #import"MyClass.h" #import"MyClass_private.h" |
如果您希望避免顶部的
MyClass
1 2 3 4 5 6 7 8 9 | interface MyClass : NSObject { @private BOOL publicIvar_; BOOL privateIvar_; } @property (nonatomic, assign) BOOL publicIvar; //any other public methods. etc @end |
我的班级私人.h
1 2 3 4 5 | @interface MyClass () @property (nonatomic, assign) BOOL privateIvar; //any other private methods etc. @end |
MyClass
1 2 3 4 5 6 7 8 | #import"MyClass.h" #import"MyClassPrivate.h" @implementation MyClass @synthesize privateIvar = privateIvar_; @synthesize publicIvar = publicIvar_; @end |
私人方法的缺失有好处。可以将要隐藏的逻辑移动到单独的类中,并将其用作委托。在这种情况下,您可以将委托对象标记为私有,从外部看不到它。将逻辑移动到单独的类(可能有几个类)可以更好地设计项目。因为类变得更简单,方法被分组到具有适当名称的类中。
没有办法解决问题2。这就是C编译器(因此也是Objective-C编译器)的工作方式。如果使用xcode编辑器,则弹出的函数应使导航文件中的
正如其他人所说,在
关于代码组织的主题-我喜欢把它们放在
1 2 3 4 5 6 7 | @implementation MyClass // .. public methods # pragma mark private // ... @end |